 Microsoft(R) Pascal Reference Manual



 



 Microsoft(R) Pascal

 Reference Manual



 



 Information in this document is subject to change without notice and
 does not represent a commitment on the part of Microsoft Corporation. The
 software described in this document is furnished under a license agreement
 or nondisclosure agreement. The software may be used or copied only in
 accordance with the terms of the agreement. It is against the law to copy
 Microsoft Pascal on magnetic tape, disk, or any other medium for any
 purpose other than the purchaser's personal use.



 (C) Copyright Microsoft Corporation, 1981, 1982, 1983, 1984, l985



 If you have comments about the software or these manuals, complete the
 Software Problem Report at the back of the Microsoft Pascal Reference
 Manual and return it to Microsoft Corporation.



 Microsoft and the Microsoft logo are registered trademarks, and MS is a
 trademark of Microsoft Corporation.

 CP/M-86 is a  registered trademark, and CP/M-80 is a trademark of Digital
 Research, Inc.

 UCSD Pascal is a registered trademark of the Regents of the University of
 California



 Contents

 

 1    Introduction to Microsoft Pascal

       1.1  Levels of Microsoft Pascal
       1.2  Selected Features
       1.3  Unimplemented Features


 2    Language Overview

       2.1  Metacommands
       2.2  Programs and Compilable Parts of Programs
       2.3  Procedures and Functions
       2.4  Statements
       2.5  Expressions
       2.6  Variables
       2.7  Constants
       2.8  Identifiers
       2.9  Notation


 3    Notation

       3.1  Components of Identifiers
       3.2  Separators
       3.3  Special Symbols
       3.4  Unused characters
       3.5  Notes on Characters


 4    Identifiers

       4.1  Creating an Identifier
       4.2  Declaring an Identifier
       4.3  The Scope of Identifiers
       4.4  Predeclared Identifiers


 5    Introduction to Data Types

       5.1  What Is a Type?
       5.2  Declaring Data Types
       5.3  Type Compatibility


 6    Simple Types

       6.1  Ordinal Types
       6.2  REAL
       6.3  INTEGER4


 7    Arrays, Records, and Sets

       7.1  Arrays
       7.2  Super Arrays
       7.3  Records
       7.4  Sets


 8    Files

       8.1  Declaring Files
       8.2  The Buffer
       8.3  File Structures
       8.4  File Access Modes
       8.5  The Predelared Files: INPUT and OUTPUT
       8.6  File I/O: Extend Level
       8.7  File I/O: System Level


 9    Reference and Other Types

       9.1  Reference Types
       9.2  PACKED Types
       9.3  Procedural and Functional Types


 10   Constants

       10.1 What Is a Constant?
       10.2 Declaring Constant Identifiers
       10.3 Numeric Constants
       10.4 Character Strings
       10.5 Structured Constants
       10.6 Constant Expressions


 11   Variables and Values

       11.1 What Is a Variable?
       11.2 Declaring a Variable
       11.3 The Value Section
       11.4 Using Variables and Values
       11.5 Attributes


 12   Expressions

       12.1 Simple Type Expressions
       12.2 Boolean Expressions
       12.3 Set Expressions
       12.4 Function Designators
       12.5 Evaluating Expressions
       12.6 Other Features of Expressions


 13   Statements

       13.1 The Syntax of Pascal Statements
       13.2 Simple Statements
       13.3 Structured Statements


 14   Introduction to Procedures and Functions

       14.1 Procedures
       14.2 Functions
       14.3 Attributes and Directives
       14.4 Procedure and Function Parameters


 15   Available Procedures and Functions

       15.1 Categories of Available Procedures and Functions
       15.2 Directory of Functions and Procedures


 16   File-Oriented Procedures and Functions

       16.1 File System Primitive Procedures and Functions
       16.2 Textfile Input and Output
       16.3 Extend Level I/O


 17   Compilable Parts of a Program

       17.1 Programs
       17.2 Modules
       17.3 Units


 18   Microsoft Pascal Metacommands

       18.1 Language Level Setting and Optimization
       18.2 Debugging and Error Handling
       18.3 Source File Control
       18.4 Listing File Control
       18.5 Listing File Format


 Appendices

 A    Pascal Syntax Diagrams

 B    Microsoft Pascal Features and the ISO Standard

 C    Microsoft Pascal and Other Pascals

 D    ASCII Character Codes

 E    Summary of Microsoft Pascal Reserved Words

 F    Summary of Available Procedures and Functions

 G    Summary of Microsoft Pascal Metacommands


 Figures

 Figure 17.1    A Microsoft Pascal Unit

 Figure 17.2    Unit with file X.INT


 Tables

 Table 2.1    Summary of Microsoft Pascal Statements

 Table 3.1    Summary of Punctuation in Microsoft Pascal

 Table 3.2    Equivalent ASCII Characters

 Table 4.1    Declaring Identifiers

 Table 5.1    Categories of Types in Microsoft Pascal

 Table 9.1    Relative and Segmented Machine Addresses

 Table 10.1   INTEGER, WORD, and INTEGER4 Constants

 Table 10.2   Constant Conversions

 Table 10.3   Constant Operators and Functions

 Table 11.1   Attributes for Variables

 Table 12.1   Expressions

 Table 12.2   Set Operators

 Table 13.1   Microsoft Pascal Statements

 Table 14.1   Attributes and Directives for Procedures and Functions

 Table 15.1   Categories of Available Procedures and Functions

 Table 15.2   File System Procedures and Functions

 Table 15.3   Predeclared Arithmetic Functions

 Table 15.4   REAL Functions From the Microsoft FORTRAN Runtime Library

 Table 15.5   String Procedures and Functions

 Table 16.1   File System Procedures and Functions

 Table 16.2   Lazy Evaluation

 Table 18.1   Metacommand Notation

 Table 18.2   Language and Optimization Level

 Table 18.3   Debugging and Error Handling

 Table 18.4   Source File Control

 Table 18.5   Listing File Control Metacommands

 Table C.1    Microsoft Pascal and UCSD Pascal

 Table D.1    ASCII Character Codes

 Table F.1    Procedures and Functions

 Table G.1    Microsoft Pascal Metacommands



 How to Use This Manual

 Chapter 1, "Introduction to Microsoft Pascal," introduces the reader to the
 selected and unimplemented features of the Microsoft Pascal language and
 gives a brief overview of the standard, extend, and system levels of
 Microsoft Pascal programming.

 Chapter 2, "Language Overview," paints a broad picture of Microsoft Pascal,
 from the largest elements of the language to the smallest.

 Chapters 3 through 11 describe the elements of the language including
 notation and identifier conventions, conventions for data transfer (file
 I/O), available data structures, and the data types through which these
 data structures are accessed.

 Chapters 12 and 13 define the expressions and statements that are
 supported by Microsoft Pascal.

 Chapters 14 through 18 describe the procedures, functions, and metalanguage
 supported by Microsoft Pascal.

 Appendices A through G contain supplementary material including a
 discussion of Microsoft Pascal features, and summaries of Microsoft Pascal
 procedures, functions, metalanguage, and syntax.



 Chapter 1  Introduction to Microsoft Pascal

 

 1.1  Levels of Microsoft Pascal

 1.2  Selected Features

 1.3  Unimplemented Features



 Microsoft(R) Pascal offers systems programmers a clean, structured language
 that is especially adept at quickly handling complex financial and
 scientific algorithms. By generating native code, Microsoft Pascal offers
 the advantages of a high level programming language without sacrificing
 speed. Low level escapes to the machine level allow Microsoft Pascal
 programs to achieve speeds comparable to assembly language.

 Microsoft Pascal offers fast numeric processing in the 8087 processing
 environment and also provides 8087 emulation in the system software
 package.


 1.1  Levels of Microsoft Pascal


 MS(TM)-Pascal is organized into three levels: standard, extend, and
 system. The features of each level are discussed in more detail in Appendix
 B, "Microsoft Pascal Features and the ISO Standard." Briefly, the
 differences among the three levels are as follows:

     1.  Standard level

         At the standard level, programs must conform to the ISO standard.
         Programs you create at this level are portable to and from machines
         running other ISO-compatible Pascal compilers. There are some
         minor MS-Pascal extensions to the standard that won't be caught as
         errors at this level. For details of these extensions, as well as
         other issues regarding the ISO standard, see Appendix B, "Microsoft
         Pascal Features and the ISO Standard." In this manual, the phrases
         "standard Pascal," "the ISO standard," and "at the standard level
         of MS-Pascal" are generally synonymous.

     2.  Extend level

         The extend level is intended for structured and relatively safe
         extensions to the ISO standard. Programs you create at this level
         are portable among all machines that run MS-Pascal.

     3.  System level

         The system level includes all features available at the extend
         level. It also includes some unstructured, machine-oriented
         extensions, such as address types and the ability to access all
         file control block fields, which are useful for systems
         programming.

 In this manual, extensions to standard Pascal are called "features." A
 complete list of these features and the level at which they are available
 is given in Appendix B, "Microsoft Pascal Features and the ISO Standard."
 Selected features are described briefly in the following list.

 In addition to these three levels, MS-Pascal has a large number of
 "metacommands," that is, directives with which you can control the
 compiler. See Chapter 18, "Microsoft Pascal Metacommands," for more
 information.


 1.2  Selected Features


 The following list includes several of the features available at the extend
 and system levels of MS-Pascal. For a complete list, see Section B.2,
 "Summary of Microsoft Pascal Features."

     1.  Underscore in identifiers, which improves readability.

     2.  Nondecimal numbering (hexadecimal, octal, and binary), which
         facilitates programming at the byte and bit level.

     3.  Structured constants, which you may declare in the declaration
         section of a program or use in statements.

     4.  Variable length strings (type LSTRING), as well as special
         predeclared procedures and functions for LSTRINGs, which enhance
         standard Pascal's string handling capabilities.

     5.  Super arrays, which are special variable length arrays whose
         declaration permits passing arrays of different lengths to a
         reference parameter, as well as dynamic allocation of arrays of
         different lengths.

     6.  Predeclared unsigned BYTE (0-255) and WORD (0-65535) types, which
         facilitate programming at the system level.

     7.  Address types (segmented and unsegmented), which allow manipulation
         of actual machine addresses at the system level.

     8.  String reads, which allow the standard procedures READ and READLN
         to read strings as structures rather than character by character.

     9.  Interface to assembly language, provided by PUBLIC and EXTERN
         procedures, functions, and variables, which allows low-level
         interfacing to assembly language and library routines.

    10.  VALUE section, where you may declare the initial constant values of
         variables in a program.

    11.  Function return values of a structured type as well as of a simple
         type.

    12.  Direct (random access) files, accessible with the SEEK procedure,
         which enhance standard Pascal's file accessing capabilities.

    13.  Lazy evaluation, a special internal mechanism for interactive files
         which allows normal interactive input from terminals.

    14.  Structured BREAK and CYCLE statements, which allow structured exits
         from a FOR, REPEAT, or WHILE loop; and the RETURN statement, which
         allows a structured exit from a procedure or function.

    15.  OTHERWISE in CASE statements, whereby you avoid explicitly
         specifying each CASE constant. OTHERWISE is also permitted with
         variant records.

    16.  STATIC attribute for variables, which allows you to indicate that a
         variable is to be allocated at a fixed location in memory rather
         than on the stack.

    17.  ORIGIN attribute, which may be given to variables, procedures, and
         functions to indicate their absolute location in memory.

    18.  INTERRUPT attribute for procedures, which signals the compiler to
         give the procedure a special calling sequence that saves the
         machine status on the stack upon entry and restores the machine
         status upon exit.

    19.  Separate compilation of portions of a program (units and modules).

    20.  Conditional compilation, which uses conditional metacommands in
         your MS-Pascal source file to switch on or off compilation of parts
         of the source.


 1.3  Unimplemented Features


 The following features either are not presently implemented or are
 implemented only as described in the following list:

     1.  OTHERWISE is not accepted in RECORD declarations.

     2.  Code is generated for PURE functions, but no checking is done.

     3.  The extend level operators SHL, SHR, and ISR are not available.

     4.  ENABIN, DISBIN, and VECTIN library routines are not available. The
         INTERRUPT attribute is ignored.

     5.  No checking is done for invalid GOTOs and uninitialized REAL
         values.

     6.  READ, READLN, and DECODE cannot have M and N parameters.

     7.  Enumerated I/O, for reading and writing enumerated constants as
         strings, is not available.

     8.  The metacommands $tagck, $standard, $extend, and $system can be
         given, but have no effect.

     9.  The $inconst metacommand does not accept string constants.



 Chapter 2  Language Overview

 

 2.1  Metacommands

 2.2  Programs and Compilable Parts of Programs

 2.3  Procedures and Functions

 2.4  Statements

 2.5  Expressions

 2.6  Variables

 2.7  Constants

       2.7.1  Types

 2.8  Identifiers

 2.9  Notation



 In this chapter you will find a summary description of Microsoft Pascal
 from the largest elements of the language to the smallest. Each of the
 remaining chapters of the manual discusses these elements in detail, from
 the smallest element (notation) to the largest (metacommands).


 2.1  Metacommands


 The MS-Pascal metacommands provide a control language for the MS-Pascal
 Compiler. The metacommands let you specify options that affect the overall
 operation of a compilation. For example, you can conditionally compile
 different source files, generate a listing file, or enable or disable
 runtime error checking code.

 Metacommands are inserted inside comment statements. All of the
 metacommands begin with a dollar sign ($). Some may also be given as
 switches when you invoke the compiler.

 Although most implementations of Pascal have some type of compiler
 control, the MS-Pascal metacommands are not part of standard Pascal and
 hence are not portable.

 These are the metacommands currently available:

      $brave                    $page
      $debug                    $pageif
      $decmath                  $pagesize
      $entry                    $pop
      $errors                   $push
      $extend                   $rangeck
      $floatcalls               $real
      $goto                     $rom
      $include                  $runtime
      $inconst                  $simple
      $indexck                  $size
      $initck                   $skip
      $if $then $else $end      $speed
      $integer                  $stackck
      $line                     $standard
      $linesize                 $subtitle
      $list                     $symtab
      $mathck                   $system
      $message                  $tagck
      $nilck                    $title
      $ocode                    $warn
      $optbug

 See Chapter 18, "Microsoft Pascal Metacommands," for a complete
 discussion of metacommands.


 2.2  Programs and Compilable Parts of Programs


 The MS-Pascal Compiler processes programs, modules, and implementations
 of units. Collectively, these compilable programs and parts of programs
 are referred to as compilands. You can compile modules and implementations
 of units separately and then later link them to a program without having to
 recompile the module or unit.

 The fundamental unit of compilation is a program. A program has three
 parts:

     1.  The program heading identifies the program and gives a list of
         program parameters.

     2.  The declaration section follows the program heading and contains
         declarations of labels, constants, types, variables, functions, and
         procedures. Some of these declarations are optional.

     3.  The body follows all declarations. It is enclosed by the reserved
         words BEGIN and END and is terminated by a period. The period is
         the signal to the compiler that it has reached the end of the
         source file.

 The following program illustrates this three-part structure:

      {Program heading}
      PROGRAM FRIDAY (INPUT, OUTPUT);

      {Declaration section}
      LABEL 1;
      CONST DAYS_IN_WEEK = 7;
      TYPE KEYBOARD_INPUT = CHAR;
      VAR KEYIN : KEYBOARD_INPUT;

      {Program body}
      BEGIN
         WRITE('IS TODAY FRIDAY? ');
      1: READLN(KEYIN);
         CASE KEYIN OF
          'Y', 'y' : WRITELN('It''s Friday.');
          'N', 'n' : WRITELN('It''s not Friday.');
         OTHERWISE
            WRITELN('Enter Y or N.');
            WRITE('Please re-enter: ');
            GOTO 1
         END
      END.

 This three-part structure (heading, declaration section, and body) is used
 throughout the Pascal language. Procedures, functions, modules, and units
 are all similar in structure to a program.

 Modules are program-like units of compilation that contain the declaration
 of variables, constants, types, procedures, and functions, but no program
 statements. You can compile a module separately and later link it to a
 program, but it cannot be executed by itself.

 Example of a module:

      {Module heading}
      MODULE MODPART;

      {Declaration section}
      CONST PI = 3.14;

      PROCEDURE PARTA;
         BEGIN
           WRITELN ('parta')
         END;

      {Body}
      END.

 A module, like a program, ends with a period. Unlike a program, a
 module contains no program statements.

 A unit has two sections: an interface and an implementation. Like a
 module, an implementation may be compiled separately and later linked to
 the rest of the program. The interface contains the information that lets
 you connect a unit to other units, modules, and programs.

 Example of a unit:

      {Heading for interface}
      INTERFACE;
      UNIT MUSIC (SING, TOP);

      {Declarations for interface}
      VAR TOP : INTEGER;
      PROCEDURE SING;

      {Body of interface}
      BEGIN
      END;

      {Heading for implementation}
      IMPLEMENTATION OF MUSIC;

      {Declaration for implementation}
      PROCEDURE SING;
      BEGIN
         FOR I := 1 TO TOP DO
         BEGIN
           WRITE ('FA '); WRITELN ('LA LA')
         END
      END;

      {Body of implementation}
      BEGIN
         TOP := 5
      END.

 A unit, like a program or a module, ends with a period.

 Modules and units let you develop large structured programs that can be
 broken into parts. This practice is advantageous in the following
 situations:

     1.  If a program is large, breaking it into parts makes it easier to
         develop, test, and maintain.

     2.  If a program is large and recompiling the entire source file is
         time consuming, breaking the program into parts saves compilation
         time.

     3.  If you intend to include certain routines in a number of different
         programs, you can create a single object file that contains these
         routines and then link it to each of the programs in which the
         routines are used.

     4.  If certain routines have different implementations, you might place
         them in a module to test the validity of an algorithm and later
         create and implement similar routines in assembly language to
         increase the speed of the algorithm.

 See Chapter 17, "Compilable Parts of a Program," for a complete
 discussion of programs, modules, and units.


 2.3  Procedures and Functions


 Procedures and functions act as subprograms that execute under the
 supervision of a main program. However, unlike programs, procedures and
 functions can be nested within each other and can even call themselves.
 Furthermore, they have sophisticated parameter-passing capabilities that
 programs lack.

 Procedures are invoked as statements; functions can be invoked in
 expressions wherever values are called for.

 A procedure declaration, like a program, has a heading, a declaration
 section, and a body.

 Example of a procedure declaration:

      {Heading}
      PROCEDURE COUNT_TO (NUM : INTEGER);

      {Declaration section}
      VAR I : INTEGER;

      {Body}
      BEGIN
        FOR I := 1 TO NUM DO WRITELN (I)
      END;

 A function is a procedure that returns a value of a particular type;
 hence, a function declaration must indicate the type of the return value.

 Example of a function declaration:

      {Heading}
      FUNCTION ADD (VAL1, VAL2 : INTEGER) : INTEGER;

      {Declaration section empty}

      {Body}
      BEGIN
         ADD := VAL1 + VAL2
      END;

 Procedures and functions look somewhat different from programs, in that
 their parameters have types and other options. Like the body of a program,
 the body of a procedure or a function is enclosed by the reserved words
 BEGIN and END; however, a semicolon rather than a period follows the word
 "END".

 Declaring a procedure or function is entirely distinct from using it in
 a program.

 For example, the procedure and function declared above might actually
 appear in a program as follows:

      TARGET_NUMBER := ADD (5, 6);
      COUNT_TO (TARGET_NUMBER);

 See Chapter 14, "Introduction to Procedures and Functions," for a
 complete discussion of procedures and functions.

 See Chapter 15, "Available Procedures and Functions," and Chapter 16,
 "File-Oriented Procedures and Functions," for a discussion of procedures
 and functions that are predeclared as part of the MS-Pascal language.


 2.4  Statements


 Statements perform actions, such as computing, assigning, altering the
 flow of control, and reading and writing files. Statements are found in the
 bodies of programs, procedures, and functions and are executed as a program
 runs. MS-Pascal statements perform the actions shown in Table 2.1.


 Table 2.1
 Summary of Microsoft Pascal Statements
ķ
 Statement    Purpose
 
 Assignment   Replaces the current value of a variable with a new
              value

 BREAK        Exits the currently executing loop

 CASE         Allows for the selection of one action from a choice
              of many, based on the value of an expression

 Statement    Purpose

 CYCLE        Starts the next iteration of a loop

 FOR          Executes a statement repeatedly while a progression
              of values is assigned to a control variable

 GOTO         Continues processing at another part of the
              program

 IF           Together with THEN and ELSE, allows for
              conditional execution of a statement

 Procedure    Invokes a procedure with actual parameter
 call         values

 REPEAT       Repeats a sequence of statements one or more times,
              until a Boolean expression becomes true

 RETURN       Exits the current procedure, function, program, or
              implementation
 Statement    Purpose
             implementation

 WHILE        Repeats a statement zero or more times, until a
              Boolean expression becomes false

 WITH         Opens the scope of a statement to include the fields
              of one or more records, so that you can refer to the
              fields directly

 See Chapter 13, "Statements," for a detailed discussion of each of
 these statements.


 2.5  Expressions


 An expression is a formula for computing a value. It consists of a
 sequence of operators (which indicate the action to be performed) and
 operands (which are the value on which the operation is performed).
 Operands may contain function invocations, variables, constants, or even
 other expressions. In the following expression, plus (+) is an operator,
 while A and B are operands:

      A + B

 There are three basic kinds of expressions:

     1.  Arithmetic expressions perform arithmetic operations on the
         operands in the expression.

     2.  Boolean expressions perform logical and comparison operations with
         Boolean results.

     3.  Set expressions perform combining and comparison operations on
         sets, with Boolean or set results.

 Expressions always return values of a specific type. For instance, if
 A, B, C, and D are all REAL variables, then the following expression
 evaluates to a REAL result:

      A * B + (C / D) + 12.3

 Expressions may also include function designators:

      ADDREAL (2, 3) + (C / D)

 ADDREAL is a function that has been previously declared in a program. It
 has two REAL value parameters, which it adds together to obtain a total.
 This total is the return value of the function, which is then added to
 (C / D).

 Expressions are not statements, but may be components of statements. In
 the following example, the entire line is a statement; only the portion
 after the equal sign is an expression:

      X := 2 / 3 + A * B

 See Chapter 12, "Expressions," for a detailed discussion of expressions.


 2.6  Variables


 A variable is a value that is expected to change during the course of a
 program. Every variable must be of a specific data type.

 After you declare a variable in the heading or declaration section of a
 compiland, procedure, or function, it may be used in any of the following
 ways:

     1.  You may initialize it, in the VALUE section of a program.

     2.  You may assign it a value, with an assignment statement.

     3.  You may pass it as a parameter to a procedure or function.

     4.  You may use it in an expression.

 The VALUE section is an MS-Pascal feature that applies only to
 statically allocated variables (variables with a fixed address in memory).
 First you declare the variables, as shown in the following example:

      VAR  I, J, K, L : INTEGER;

 Then you assign them initial values in the VALUE section:

      VALUE  I := 1; J := 2; K := 3; L := 4;

 Later, in statements, the variables can be assigned to, and used as
 operands in expressions:

      I := J + K + L;
      J := 1 + 2 + 3;
      K := (J * K) + 9 + (L DIV J);

 See Chapter 11, "Variables and Values," for a complete discussion of
 variables.


 2.7  Constants


 A constant is a value that is not expected to change during the course
 of a program. At the standard level, a constant may be:

     1.  a number, such as 1.234 and 100

     2.  a string enclosed in single quotation marks, such as 'Miracle' or
         'A1207'

     3.  a constant identifier that is a synonym for a numeric or string
         constant

 You declare constant identifiers in the CONST section of a compiland,
 procedure, or function.

      CONST  REAL_CONST = 1.234;
             MAX_VAL = 100;
             TITLE = 'Pascal';

 Because the order of declarations is flexible in MS-Pascal, you can declare
 constants anywhere in the declaration section of a compilable part of a
 program, any number of times.

 Constants are closely tied to the concepts of variables and types.
 Variables are all of some type; types, in turn, designate a range of
 assumable values. These values, ultimately, are all constants.

 Two powerful extensions in MS-Pascal are structured constants and
 constant expressions.

     1.  VECTOR, in the following example, is an array constant:

             CONST VECTOR = VECTORTYPE (1, 2, 3, 4, 5);

     2.  MAXVAL, in the following example, is a constant expression (A, B,
         C, and D must also be constants):

             CONST MAXVAL = A * (B DIV C) + D - 5;

 See Chapter 10, "Constants," for a complete discussion of these and
 other aspects of constants.


 2.7.1  Types


 Much of MS-Pascal's power and flexibility lies in its data typing
 capability. Although a great variety of data types are available, they may
 be divided into three broad categories: simple, structured, and reference
 types.

     1.  A simple data type represents a single value. The simple types
         include the following:

         INTEGER     enumerated
         WORD        subrange
         CHAR        REAL
         BOOLEAN     INTEGER4

     2.  A structured data type represents a collection of values. The
         structured types include the following:

         ARRAY
         RECORD
         SET
         FILE

     3.  Reference types allow recursive definition of types.

 All variables in MS-Pascal must be assigned a data type. A type is
 either predeclared (e.g., INTEGER and REAL) or defined in the declaration
 section of a program. The following sample type declaration creates a type
 that can store information about a student:

      TYPE
         STUDENT = RECORD
            AGE : 5..18;
            SEX : (MALE, FEMALE);
            GRADE : INTEGER;
            GRADE_PT : REAL;
            SCHEDULE : ARRAY [1..10] OF CLASSES
         END;

 For a detailed discussion of data types, see the following chapters:

      Chapter 5, "Introduction to Data Types"
      Chapter 6, "Simple Types"
      Chapter 7, "Arrays, Records, and Sets"
      Chapter 8, "Files"
      Chapter 9, "Reference and Other Types"


 2.8  Identifiers
 Identifiers are names that denote the constants, variables, data types,
 procedures, functions, and other elements of a Pascal program. Procedures
 and functions must have identifiers; constants, type, and variables may
 have identifiers (and it is useful if they do).

 You, the programmer, make up most of the identifiers in a program and
 assign them meaning in declarations. Other identifiers are the names of
 variables, data types, procedures, and functions that are built into the
 language and need not be declared.

 An identifier must begin with a letter (A through Z and a through z).
 The initial letter may be followed by any number of letters, digits (0
 through 9), or underscore characters.

 The underscore in MS-Pascal is significant. Thus, the following are not
 identical:

      FOREST
      FOR_EST

 The only restriction on identifiers is that you must not choose a Pascal
 reserved word (see Section 3.3.2, "Reserved Words," for a discussion of
 reserved words; see Appendix E," Summary of Microsoft Pascal Reserved
 Words," for a complete list).

 Furthermore, most compilers have some restriction either on the
 absolute length of an identifier or on the number of characters that are
 considered significant. See Appendix B, "Version Specifics," in your
 Microsoft Pascal Compiler User's Guide for any limitations imposed by your
 version of the compiler.

 See Chapter 4, "Identifiers," for a complete discussion of identifiers
 in MS-Pascal.


 2.9  Notation


 The basis of all Pascal programs is an irreducible set of symbols with
 which the higher syntactic components of the language are created.

 The underlying notation is the ASCII character set, divided into the
 following syntactic groups:

     1.  Identifiers are the names given to individual instances of
         components of the language.

     2.  Separators are characters that delimit adjacent numbers, reserved
         words, and identifiers.

     3.  Special symbols include punctuation, operators, and reserved words.

     4.  Some characters are unused by MS-Pascal but are available for use
         in a comment or string literal.

 A good understanding of this notation will increase your productivity by
 reducing the number of subtle syntactic errors in a program. See
 Chapter 3, "Notation," for a detailed discussion of MS-Pascal notation.



 Chapter 3  Notation

 

 3.1  Components of Identifiers

       3.1.1  Letters

       3.1.2  Digits

       3.1.3  The Underscore Character

 3.2  Separators

 3.3  Special Symbols

       3.3.0 Punctuation

       3.3.1  Operators

       3.3.2  Reserved Words

 3.4  Unused Characters

 3.5  Notes on Characters



 All components of the Microsoft Pascal language are constructed from the
 standard ASCII character set. Characters make up lines, each of which is
 separated by a character specific to your operating system. Lines make up
 files.

 Within a line, individual characters or groups of characters fall into
 one (or more) of four broad categories:

     1.  components of identifiers

     2.  separators

     3.  special symbols

     4.  unused characters


 3.1  Components of Identifiers


 Identifiers are names that denote the constants, variables, data types,
 procedures, functions, and other elements of a Pascal program.

 The use of identifiers is described thoroughly in Chapter 4,
 "Identifiers." This section discusses only how to construct them.

 Identifiers must begin with a letter; subsequent components may include
 letters, digits, and underscore characters.

 Although, in theory, there is no limit on the number of characters in
 an identifier, most implementations restrict the length in some way. See
 Appendix B, "Version Specifics," in your Microsoft Pascal Compiler User's
 Guide for any limitations that may apply to your machine.


 3.1.1  Letters


 In identifiers, only the uppercase letters A through Z are significant.
 You may use lowercase letters for identifiers in a source program.
 However, the MS-Pascal Compiler converts all lowercase letters in
 identifiers to the corresponding uppercase letters.

 Letters in comments or in string literals may be either uppercase or
 lowercase; the difference is significant. No mapping of lowercase to
 uppercase occurs in either comments or string literals.


 3.1.2  Digits


 Digits in Pascal are the numbers zero through nine. Digits can occur in
 identifiers (for example, AS129M) or in in numeric constants (for
 example, 1.23 and 456).


 3.1.3  The Underscore Character


 The underscore (_) is the only nonalphanumeric character allowed in
 identifiers. The underscore is significant in MS-Pascal. Use it like a
 space to improve readability.

 The identifiers in the left-hand column below demonstrate how the
 underscore improves readability. Note, however, that they will not be
 equal to those in the right-hand column.

      POWER_OF_TEN          POWEROFTEN
      MY_DOG_MAUDE          MYDOGMAUDE


 3.2  Separators


 Separators delimit adjacent numbers, reserved words, and identifiers,
 none of which should have separators embedded within them.

 A separator can be any of the following:

     1.  the space character

     2.  the tab character

     3.  the form feed character

     4.  the new line marker

     5.  the comment

 Comments in standard Pascal take one of these forms:

      {This is a comment, enclosed in braces.}
      (*This is an alternate form of comment.*)

 The second form is generally used if braces are unavailable on a particular
 machine. Comments in either of these forms may span more than one line.

 At the extend level, MS-Pascal also allows comments that begin with an
 exclamation point:

      ! The rest of this line is a comment.

 For comments in this form, the new line character delimits the comment.

 Nested comments are permitted in MS-Pascal, so long as each level has
 different delimiters. Thus, when a comment is started, the compiler
 ignores succeeding text until it finds the matching end-of-comment.
 However, such nesting may not be portable.

 Always use separators between identifiers and numbers. If you fail to
 do so, the compiler will generally issue an error or warning message. In a
 few cases, the MS-Pascal Compiler accepts a missing separator without
 generating an error message.

 For example, at extend level,

      100MOD#127

 is accepted as 100 MOD #127, where #127 is a hexadecimal number. However,

      100MOD127

 is assumed to be 100 followed by the identifier MOD127.


 3.3  Special Symbols


 Special symbols fall into three categories:

     1.  punctuation

     2.  operators

     3.  reserved words


 3.3.0 Punctuation

 Punctuation in MS-Pascal serves a variety of purposes, including those
 shown in Table 3.1.


 Table 3.1.
 Summary of Punctuation in Microsoft Pascal
ķ
 Symbol Purpose
 
 {  }   Braces delimit comments.

 [  ]   Brackets delimit array indices, sets, and attributes.
        They may also replace the reserved words BEGIN and END in
        a program.

 (  )   Parentheses delimit expressions, parameter lists, and
        program parameters.

 Symbol Purpose

 '      Single quotation marks enclose string literals.

 :=     The colon-equal symbol assigns values to variables in
        assignment statements and in VALUE sections.

 ;      The semicolon separates statements and declarations.

 :      The colon separates variables from types and labels from
        statements.

 =      The equal sign separates identifiers and type clauses in a
        TYPE section.

 ,      The comma separates the components of lists.

 ..     The double period denotes a subrange.

 .      The period designates the end of a program, indicates the
        fractional part of a real number, and also delimits fields
 Symbol Purpose
       fractional part of a real number, and also delimits fields
        in a record.

 ^      The up arrow denotes the value pointed to by a reference
        value.

 #      The number sign denotes nondecimal numbers.

 $      The dollar sign prefixes metacommands.


 3.3.1  Operators


 Operators are a form of punctuation that indicate some operation to be
 performed. Some are alphabetic, others are one or two nonalphanumeric
 characters. Any operators that consist of more than one character must not
 have a separator between characters.

 The operators that consist only of nonalphabetic characters are the
 following:

     +   -   *   /   >   <  =   <>  <=  >=

 Some operators (e.g., NOT and DIV) are reserved words instead of
 nonalphabetic characters.

 See Chapter 12, "Expressions," for a complete list of the nonalphabetic
 operators and a discussion of the use of operators in expressions.


 3.3.2  Reserved Words


 Reserved words are a fixed part of the MS-Pascal language. They include,
 for example, statement names (e.g., BREAK) and words like BEGIN and END
 that bracket the main body of a program. See Appendix E, "Summary of
 Microsoft Pascal Reserved Words," for a complete list.

 You cannot create an identifier that is the same as any reserved word.
 You may, however, declare an identifier that contains within it the letters
 of a reserved word (for example, the identifier DOT containing the reserved
 word DO).

 There are several categories of reserved words in MS-Pascal:

     1.  reserved words for standard level MS-Pascal

     2.  reserved words added for extend level MS-Pascal features

     3.  reserved words added for system level MS-Pascal features

     4.  names of attributes

     5.  names of directives

 See Appendix E, "Summary of Microsoft Pascal Reserved Words," for a
 complete list of reserved words. Look in the index for the pages where
 each is discussed in this manual.


 3.4  Unused Characters


 A few printing characters are not used in MS-Pascal:

     %   &   "   |   ~

 You may, however, use them within comments or string literals.

 A number of other nonprinting ASCII characters will generate error
 messages if you use them in a source file other than in a comment or string
 literal:

     1.  the characters from CHR (0) to CHR (31), except the tab and form
         feed, CHR (9) and CHR (12), respectively

     2.  the characters from CHR (127) to CHR (255)

 The tab character, CHR (9), is treated like a space and is passed on
 to the listing file. A form feed, CHR (12), is treated like a space and
 starts a new page in the listing file.


 3.5  Notes on Characters


 This section discusses special notational properties of the MS-Pascal
 language not mentioned elsewhere in this chapter. Characters within a
 comment or string literal are always legal and have no special effects.

 MS-Pascal allows the following substitutions:

     If Your Keyboard Lacks    Use This Instead
     
     [                         (.
     ]                         .)
     ^                         @ or ?
     @                         ^ or ?

 The substitution of a question mark (?) for an up arrow (_) is a
 minor extension to the ISO standard.

 Table 3.2 gives a list of pairs of printing characters that are the
 same ASCII character.


 Table 3.2
 Equivalent ASCII Characters
ķ
 ASCII       Prints as   Equivalent Characters
 
 CHR (94)    ^           up arrow, caret
 CHR (95)    -           underscore, left arrow
 CHR (35)    #           number sign, English poound sign
 CHR (36)    $           dollar sign, scarab (circle with
                         four spikes)



 Chapter 4  Identifiers

 

 4.1  Creating an Identifier

 4.2  Declaring an Identifier

 4.3  The Scope of Identifiers

 4.4  Predeclared Identifiers



 Procedures and functions must have identifiers. Constants, types, and
 variables may have identifiers and it is useful if they do. Some
 identifiers are predeclared; others you declare in a declaration section.


 4.1  Creating an Identifier


 Standard Pascal allows identifiers for the following elements of the
 Pascal language:

      types
      constants
      variables
      procedures
      functions
      programs
      fields and tag fields in records

 The following Microsoft Pascal features at the extend level also allow
 identifiers:

      super array types
      modules
      units
      statement labels

 An identifier consists of a sequence of alphanumeric characters or
 underscore characters. The first character must be alphabetic. Underscores
 in identifiers are allowed, and significant, at all levels of MS-Pascal.
 Two underscores in a row or an underscore at the end of an identifier are
 permitted.

 Subject to the restrictions noted below, identifiers can be as long as
 you want. They must, however, fit on a single line. At least the first 19
 characters of an identifier are significant; in some versions of MS-Pascal,
 as many as 31 characters are significant.

 An identifier longer than the significance length generates a warning
 but not an error message; the excess characters are ignored by the
 compiler. See Appendix B, "Version Specifics," in your Microsoft Pascal
 Compiler User's Guide for the significance length in your implementation.

 Standard Pascal allows unsigned integers as statement labels.
 Statement labels have the same scope rules as identifiers (see Section
 4.3, "The Scope of Identifiers"). Leading zeros are not significant. Extend
 level MS-Pascal allows labels that are normal alphabetic identifiers.

 The identifiers used for a program, module, or unit, as well as
 identifiers with the PUBLIC or EXTERN attribute, are passed to the linker.
 The operating system of a machine on which you plan to link and run a
 compiled MS-Pascal program may impose further identifier length
 restrictions on identifiers used as linker global symbols. Furthermore,
 the object code listing and debugger symbol table may truncate variable and
 procedural identifiers to six characters.

 Writing programs for use with other compilers and operating systems
 imposes an additional constraint on a program. Such a program must conform
 to the identifier restrictions for the worst possible case.

 For portability in general, the following practices are recommended:

     1.  Make all identifiers unique in their first eight characters.

     2.  Make external identifiers unique in their first six characters.

     3.  Limit statement labels to four digits without leading zeros.

 Identifiers of seven characters or fewer save space during compilation.

 
 Note
   All identifiers used internally by the runtime system are four alphabetic
   characters followed by the characters QQ. Avoid this form when creating
   new names yourself.
 


 4.2  Declaring an Identifier


 You declare identifiers and associate them with language objects in the
 declaration section of a program, module, interface, implementation,
 procedure, or function. Examples of identifiers, the objects they
 represent, and the syntax used to declare them are shown in Table 4.1.
 Although the details vary, the basic form of the declaration of the
 identifier for each of these elements is similar.


 Table 4.1.
 Declaring Identifiers
ķ
 Object           Identifier         Declaration
 
 Program          Z                  PROGRAM Z (INPUT, OUTPUT)
 Module           XXX                MODULE XXX
 Object           Identifier         Declaration
Module           XXX                MODULE XXX
 Interface        UUU                INTERFACE; UNIT UUU
 Implementation   UUU                IMPLEMENTATION of UUU
 Constant         DAYS               CONST DAYS = 365
 Type             LETTERS            TYPE LETTERS = 'A'..'Z'
 Record fields    X, Y, Z            TYPE A = RECORD
                                         X, Y ,Z : REAL END
 Variable         J                  VAR J : INTEGER
 Label            1                  LABEL 1
 Label            HAWAII             LABEL HAWAII
 Procedure        BANG               PROCEDURE BANG
 Function         FOO                FUNCTION FOO : INTEGER


 4.3  The Scope of Identifiers


 An identifier is defined for the duration of the procedure, function,
 program, module, implementation, or interface in which you declare it.
 This holds true for any nested procedures or functions. An identifier's
 association must be unique within its scope; that is, it must not name more
 than one thing at a time.

 A nested procedure or function can redefine an identifier only if the
 identifier has not already been used in it. However, the compiler does not
 identify such redefinition as an error, but will generally use the first
 definition until the second occurs. A special exception for reference types
 is discussed in Section 9.1.5, "Notes on Reference Types."


 4.4  Predeclared Identifiers


 A number of identifiers are already a part of the MS-Pascal language.
 This category includes the identifiers for predeclared types, super array
 types, constants, file variables, functions, and procedures. You can use
 them freely, without declaring them. However, they differ from reserved
 words in that you may redefine them whenever you wish.

 At the standard level, the following identifiers are predeclared:

      ABS          FLOAT        PACK         SIN
      ARCTAN       GET          PAGE         SQR
      BOOLEAN      INPUT        PRED         SQRT
      CHAR         INTEGER      PUT          SUCC
      CHR          LN           READ         TEXT
      COS          MAXINT       READLN       TRUE
      DISPOSE      NEW          REAL         TRUNC
      EOF          ODD          RESET        UNPACK
      EOLN         ORD          REWRITE      WRITE
      EXP          OUTPUT       ROUND        WRITELN
      FALSE

 Features at the extend and system levels add the following to the list of
 predeclared identifiers in MS-Pascal.

     1.  String intrinsics

         CONCAT      INSERT
         COPYLST     POSITN
         COPYSTR     SCANEQ
         DELETE      SCANNE

     2.  Extend level intrinsics

         ABORT       LOBYTE
         BYWORD      LOWER
         DECODE      RESULT
         ENCODE      SIZEOF
         EVAL        UPPER
         HIBYTE

     3.  System level intrinsics

         FILLC       MOVESL
         FILLSC      MOVESR
         MOVEL       RETYPE
         MOVER

     4.  Extend level I/O

         ASSIGN      READFN
         CLOSE       READSET
         DIRECT      SEEK
         DISCARD     SEQUENTIAL
         FCBFQQ      TERMINAL
         FILEMODES

     5.  INTEGER4 type

         BYLONG      LOWORD
         FLOATLONG   MAXINT4
         HIWORD      ROUNDLONG
         INTEGER4    TRUNCLONG

     6.  Super array type

         LSTRING
         NULL
         STRING

     7.  WORD type

         MAXWORD
         WORD
         WRD

     8  Miscellaneous

         ADRMEM      INTEGER2
         ADSMEM      REAL4
         BYTE        REAL8
         INTEGER1    SINT



 Chapter 5  Introduction to Data Types

 

 5.1  What Is a Type?

 5.2  Declaring Data Types

 5.3  Type Compatibility

       5.3.1  Type Identity and Reference Parameters

       5.3.2  Type Compatibility and Expressions

       5.3.3  Assignment Compatibility



 Types in Microsoft Pascal fall into three broad categories: simple,
 structured, and reference types. Table 5.1 that follows gives a breakdown
 of the types in each of these groups. The remainder of this chapter
 discusses types in general; Chapters 6 through 9 discuss the different
 groups in detail.


 5.1  What Is a Type?


 A type is the set of values that a variable or value can have within a
 program. Types are either predeclared or declared explicitly.

 For example, the types INTEGER and REAL are predeclared, while the
 type ARRAY [1..10] OF INTEGER is declared explicitly. An explicitly
 declared type may also be given a type identifier. To accomplish this
 latter task, a type declaration is required.


 Table 5.1
 Catagories  of Types in Microsoft Pascal
ķ
 Category    Includes                  Comments/Examples
 
 Simple      Ordinal types
 Types         INTEGER                 -MAXINT..MAXINT
               WORD                    0..MAXWORD
               CHAR                    CHR(0)..CHR(255)
               BOOLEAN                 (FALSE,TRUE)
               enumerated types        e.g., (RED,BLUE)
               subrange types          e.g., 100..5000
             REAL4, REAL8
             INTEGER4                  -MAXINT4..MAXINT4
 Category    Includes                  Comments/Examples
            INTEGER4                  -MAXINT4..MAXINT4

 Structured  ARRAY OF type
 Types         general (OF any type)
               SUPER ARRAY (OF type)
                 STRING (n)            [1..n] of CHAR
                 LSTRING (n)           [0..n] of CHAR
             RECORD
             SET OF type
             FILE OF
               general (binary) files
               TEXT                    Like FILE OF CHAR

 Reference   Pointer Types             e.g., ^TREETIP
 Types         ADR OF type             Relative address
               ADS OF type             Segmented address

 Procedural                            Only as parameter
 and                                   type
 Functional
 Category    Includes                  Comments/Examples
Functional
 Types


 5.2  Declaring Data Types


 The type declaration associates an identifier with a type of value.
 You declare types in the TYPE section of a program, procedure, function,
 module, interface, or implementation (not in the heading of a procedure or
 function).

 A type declaration consists of an identifier followed by an equal sign
 and a type clause.

 Examples of type definitions:

     TYPE LINE = STRING (80);
          PAGE = RECORD
               PAGENUM : 1..499;
               LINES : ARRAY [1..60] OF LINE;
               FACE : (LEFT, RIGHT);
               NEXTPAGE : ^PAGE
               END;

 After declaring the data types, you declare variables of the types
 just defined in the VAR section of a program, procedure, function, module,
 or interface, or in the heading of a procedure or function. The following
 sample VAR section declares variables of the types in the preceding sample
 TYPE section:

     VAR PARAGRAPH : LINE;
         BOOK : PAGE;

 Because a type identifier is not defined until its declaration is
 processed by the compiler, a recursive type declaration such as the
 following is illegal:

     T = ARRAY [0..9] OF T;

 Reference types require a  standard exception to this rule and are
 discussed in Chapter 9, "Reference and Other Types."

 A special feature of MS-Pascal is a category called super types. A
 super type declaration determines the set of types that designators of that
 super type can assume; it also associates an identifier with the super
 type. Super type declarations also occur in the TYPE section. The only
 super types currently available in MS-Pascal are super arrays.


 5.3  Type Compatibility


 MS-Pascal follows the ISO standard for type compatibility, with some
 additional rules added for super array types, LSTRINGs, and constant
 coercions (i.e., forced changes in the type of a constant). Type transfer
 functions, to override the typing rules, are available with some MS-Pascal
 features.

 Two types can be "identical," "compatible," or "incompatible." An
 expression may or may not be "assignment compatible" with a variable, value
 parameter, or array index.


 5.3.1  Type Identity and Reference Parameters


 Two types are identical if they have the identical identifier or if the
 identifiers are declared equivalent with a type definition like the
 following:

     TYPE T1 = T2;

 "Identical" types are truly identical in MS-Pascal: there is no
 difference between types T1 and T2 in the example above. Type identity is
 based on the name of the types, and not on the way they are declared or
 structured. Thus, for example, T1 and T2 are not identical in the following
 declarations:

     TYPE T1 = ARRAY [1..10] OF CHAR;
          T2 = ARRAY [1..10] OF CHAR;

 Actual and formal reference parameters must be of identical types.
 Or, if a formal reference parameter is of a super array type, the actual
 parameter must be of the same super array type or a type derived from it.
 Two record or array types must be identical for assignment.

 The only exception is for strings. Here, actual parameters of type
 CHAR, STRING, STRING (n), LSTRING, and LSTRING (n) are compatible with a
 formal parameter super array type STRING. Also, the type of a string
 constant will change to any LSTRING type with a large enough bound. For
 example, the type of 'ABC' will change to LSTRING (5) if necessary.

 Furthermore, an actual parameter of any FILE type may be passed to a
 formal parameter of a special record type FCBFQQ. Similarly, an actual
 parameter of type FCBFQQ may be passed to a formal parameter of any file
 type. See Section 8.7, "File I/O: System Level," for a description of
 the FCBFQQ type.

 STRING (n) is a shorthand notation for:

     PACKED ARRAY [1..n] OF CHAR

 The two types are identical. However, because variables with the type
 LSTRING are treated specially in assignments, comparisons, READs, and
 WRITEs, LSTRING (n) is not a shorthand notation for PACKED ARRAY [0..n] OF
 CHAR. The two types are not identical, compatible, or assignment
 compatible. See Section 7.2.3, "Using STRINGs and LSTRINGs," for further
 information on string types.


 5.3.2  Type Compatibility and Expressions


 Two simple or reference types are compatible if any of the following is
 true:

     1.  They are identical.

     2.  They are both ADR types.

     3.  They are both ADS types.

     4.  One is a subrange of the other.

     5.  They are subranges of compatible types.

 Two structured types are compatible if any of the following is true:

     1.  They are identical.

     2.  They are SET types with compatible base types.

     3.  They are STRING derived types of equal length.

     4.  They are LSTRING derived types.

 However, two structured types are incompatible if any of the following is
 true:

     1.  Either type is a FILE or contains a FILE.

     2.  Either type is a super array type.

     3.  One type is PACKED and the other is not.

 Two values must be of compatible types when combined with an operator
 in an expression. (Most operators have additional limitations on the type
 of their operands. See Chapter 12, "Expressions," for details.) A CASE
 index expression type must be compatible with all CASE constant values.


 5.3.3  Assignment Compatibility


 Some types are implicitly compatible. This permits assignment across
 type boundaries. For instance, assume you declare the following variables:

     VAR DESTINATION : T_DEST;
         SOURCE : T_SOURCE;

 SOURCE is assignment compatible with DESTINATION (i.e.,
 DESTINATION := SOURCE is permitted) if one of the following is true:

     1.  T_SOURCE and T_DEST are identical types.

     2.  T_SOURCE and T_DEST are compatible and SOURCE has a value in the
         range of subrange type T_DEST.

     3.  T_DEST is of type REAL and T_SOURCE is compatible with type INTEGER
         or INTEGER4.

     4.  T_DEST is of type INTEGER4 and T_SOURCE is compatible with type
         INTEGER or WORD.

 Also, if T_DEST and T_SOURCE are compatible structured types, then SOURCE
 is assignment compatible with DESTINATION if one of the following is true:

     1.  For SETs, every member of SOURCE is in the base type of T_DEST.

     2.  For LSTRINGs, UPPER (DESTINATION) >= SOURCE.LEN.

 Other than in the assignment statement itself, assignment compatibility
 is required in the following cases of implicit assignment:

     1.  passing value parameters

     2.  READ and READLN procedures

     3.  control variable and limits in a FOR statement

     4.  super array type array bounds, and array indices

 Assignment compatibility is usually known at compile time, and an
 assignment generates simple instructions. However, some subrange, set, and
 LSTRING assignments depend on the value of the expression to be assigned
 and thus cannot be checked until runtime. If the range checking switch is
 on, assignment compatibility is checked at runtime; otherwise, no checking
 is done.



 Chapter 6  Simple Types

 

 6.1  Ordinal Types

       6.1.1  INTEGER

       6.1.2  WORD

       6.1.3  CHAR

       6.1.4  BOOLEAN

       6.1.5  Enumerated Types

       6.1.6  Subrange Types

 6.2  REAL

 6.3  INTEGER4



 The basic distinction between simple and structured data types is that
 simple types cannot be divided into other types, while structured types
 (discussed in Chapter 7, "Arrays, Records, and Sets," and Chapter 8,
 "Files") are composed of other types. The simple data types fall into
 three categories:

     1.  ordinal types

     2.  REAL

     3.  INTEGER4


 6.1  Ordinal Types


 Ordinal types are all finite and countable. They include the following
 simple types:

      INTEGER
      WORD
      CHAR
      BOOLEAN
      enumerated types
      subrange types

 INTEGER4, though finite and countable, is not an ordinal type.


 6.1.1  INTEGER


 INTEGER values are a subset of the whole numbers and range from -MAXINT
 through 0 to MAXINT. MAXINT is the predeclared constant 32767 (i.e.,
 2^15 - 1) for current Microsoft Pascal target machines. (The value -32768
 is not a valid INTEGER; the compiler uses it to check for uninitialized
 INTEGER and INTEGER subrange variables.)

 INTEGER is not a subrange of INTEGER4 (discussed in Section 6.3,
 "INTEGER4"). If it were, signed expressions would have to be calculated
 using the INTEGER4 type and the result converted to INTEGER.

 Expressions are always calculated using a base type, not a subrange
 type. INTEGER type constants may be changed internally to WORD type if
 necessary, but INTEGER variables cannot. INTEGER values change to REAL or
 INTEGER4 in an expression, if necessary, but not to WORD. The ORD function
 converts a value of any ordinal type to an INTEGER type.

 The predeclared type INTEGER2 is identical to INTEGER.


 6.1.2  WORD


 The WORD and INTEGER types are similar, differing chiefly in their
 range of values. Both are ordinal types. You can think of WORD values as
 either a group of 16 bits or as a subset of the whole numbers from 0 to
 MAXWORD (65535, i.e., 2^16 - 1). The WORD type is an MS-Pascal feature
 that is useful in several ways:

     1.  to express values in the range from 32768 to 65535

     2.  to operate on machine addresses

     3.  to perform primitive machine operations, such as word ANDing and
         word shifting, without using the INTEGER type and running into the
         -32768 value

 Unlike INTEGERs, all WORDs are nonnegative values. The WRD function
 changes any ordinal type value to WORD type. Like INTEGER values, WORD
 values in an expression are converted to the INTEGER4 type, if necessary.

 Having both an INTEGER and a WORD type permits mapping of 16-bit
 quantities in either of two ways:

     1.  as a signed value ranging from -32767 to +32767

     2.  as a positive value ranging from 0 to 65535.

 However, you must not mix WORD and INTEGER values in an expression
 (although doing so generates a warning rather than an error message). WORD
 and INTEGER values are not assignment compatible either.


 6.1.3  CHAR


 In MS-Pascal, CHAR values are 8-bit ASCII values. CHAR is an ordinal
 type. All 256-byte values are included in the type CHAR. In addition,
 SET OF CHAR is supported. Relational comparisons use the ASCII collating
 sequence.

 Although the line-marker character used in TEXT files is not part of
 the CHAR type in the ISO standard, some target operating systems for
 MS-Pascal may require the line-marker character to be included (e.g.,
 carriage return).

 The CHR function changes any ordinal type value to CHAR type, as long
 as ORD of the value is in the range from 0 to 255. See Appendix D, "ASCII
 Character Codes," for a complete listing of the ASCII character set.


 6.1.4  BOOLEAN


 BOOLEAN is an ordinal type with only two (predeclared) values: FALSE
 and TRUE. The BOOLEAN type is a special case of an enumerated type,
 where ORD (FALSE) is 0 and ORD (TRUE) is 1. This means that FALSE < TRUE.

 You may redefine the identifiers BOOLEAN, FALSE, and TRUE, but the
 compiler implicitly uses the ordinal (default) type in Boolean expressions
 and in IF, REPEAT, and WHILE statements.

 No function exists for changing an ordinal type value to a BOOLEAN
 type value. However, you can achieve this effect with the ODD function for
 INTEGER and WORD values, or the expression:

      ORD (value) <> 0


 6.1.5  Enumerated Types


 An enumerated type defines an ordered set of values. These values are
 constants and are enumerated by the identifiers that denote them.

 Examples of enumerated type declarations:

      FLAGCOLOR = (RED, WHITE, BLUE)
      SUITS = (CLUB, DIAMOND, HEART, SPADE)
      DOGS = (MAUDE, EMILY, BRENDAN)

 Every enumerated type is also an ordinal type. Identifiers for all
 enumerated type constants must be unique within their declaration level.

 At the extend level, the READ and WRITE procedures and the ENCODE
 and DECODE functions operate on values of an enumerated type by treating
 the actual constant identifier as a string. This means that enumerated
 values can be read directly.

 The ORD function, at the standard level, can be used to change
 enumerated values into INTEGER values; the WRD function changes enumerated
 values into WORD values.

 The RETYPE function, at system level, can be used to change INTEGER or
 WORD values to an enumerated type. For example:

      IF RETYPE (COLOR, I) = BLUE THEN WRITELN ('TRUE BLUE')

 The values obtained by applying the ORD function to the constants of
 an enumerated type always begin with zero. Thus, the values obtained for
 the type FLAGCOLOR, from the example above, are as follows:

      ORD (RED) = 0
      ORD (WHITE) = 1
      ORD (BLUE) = 2

 Enumerated types are particularly useful for representing an abstract
 collection of names, such as names for operations or commands. Modifying a
 program by adding a new value to an enumerated type is much safer than
 using raw numbers, since any arrays indexed with the type or sets based on
 the type are changed automatically.

 For example, interactive input of a command might be accomplished by
 reading the enumerated type identifier that corresponds to a command.
 Since enumerated types are ordered, comparisons like RED < GREEN may also
 be useful. At times, access to the lowest and highest values of the
 enumerated type is useful with the LOWER and UPPER functions, as in the
 following example:

     VAR TINT : COLOR;
     FOR TINT := LOWER (TINT) TO UPPER (TINT)
        DO PAINT (TINT)


 6.1.6  Subrange Types


 A subrange type is a subset of an ordinal type. The type from which the
 subset is taken is called the "host" type. Therefore, all subrange
 types are also ordinal types.

 You can define a subrange type by giving the lower and upper bounds of
 the subrange (in that order). The lower bound must not be greater than the
 upper bound, but the bounds may be equal. The subrange type is frequently
 used as the index type of an array bound or as the base type of a set. See
 Chapter 7, "Arrays, Records, and Sets," for a discussion of arrays and
 sets.

 Examples of subranges along with their host ordinal type:

     Host Ordinal        Subrange
 
     INTEGER             100..200
     WORD                WRD(1)..9
     CHAR                'A'..'Z'
     enumerated type     RED..YELLOW

 In addition, you may substitute a subrange clause for a list of values
 in the following circumstances:

     1.  when setting constants

     2.  when setting constructors

     3.  when setting CASE statement constants and record variant labels (at
         the extend level)

 Besides using the subrange type in array and set declarations, you can
 use it to help guarantee that the value of a variable is within acceptable
 bounds. If the range checking switch is on during compilation, these
 bounds are checked at runtime.

 For instance, if the logic of a program implies that a variable always
 has a value from 100 to 999, then declaring it with a subrange causes the
 compiler to check that the variable is never assigned a value outside this
 range.

 In addition, declaring a subrange type may permit the compiler to
 allocate less room and use simpler operations. For example, declaring
 BOTTLES to be the INTEGER subrange 1..100 means that the type can be
 allocated in eight bits instead of sixteen.

 Three subrange types are predeclared:

     1.  BYTE = WRD(0)..255;
         {8-bit WORD subrange}

     2.  SINT = -127..127;
         {8-bit INTEGER subrange}

     3.  INTEGER1 = SINT

 The BYTE type is particularly useful in machine-oriented applications.
 For example, the ADRMEM and ADSMEM types (see Section 9.1.2, "Address
 Types," for details) normally treat memory as an array of bytes. However,
 since the BYTE type is really a subrange of the WORD type, expressions with
 BYTE values are calculated using 16-bit instead of 8-bit arithmetic, if
 necessary.

 In some cases (for example, an assignment of a BYTE expression to a
 BYTE variable when the math checking switch is off), the compiler can
 optimize 16-bit arithmetic to 8-bit arithmetic. In general, using BYTE
 instead of WORD saves memory at the expense of BYTE-to-WORD conversions in
 expression calculations.

 At the extend level, subrange bounds can be constant expressions.
 Because the compiler assumes that the left parenthesis always starts an
 enumerated type declaration, the first expression in a subrange declaration
 must not start with a left parenthesis. For example:

      TYPE {First two are permitted.}
             FEE = (A, B, C);
             FIE = M + 2 * N .. (P - 2) * N;
             {FOO is invalid as declared.}
             FOO = (M + 2) * N .. P - 2 * N;


 6.2  REAL


 REAL values are nonordinal values of a given range and precision; the
 range of allowable values depends on the target system. Refer to the
 Microsoft Pascal Compiler User's Guide for more specific information about
 your system.

 Most MS-Pascal implementations use either the Microsoft or IEEE single
 precision real number format. These formats have a 24-bit mantissa and an
 8-bit exponent, giving about seven digits of precision and a maximum value
 of 1.701411E38. Microsoft format REAL constants are limited to the range
 1.0E-38 to 1.0E+38. There is also a decimal real format (controlled by the
 $DECMATH metacommand).

 The current version of MS-Pascal includes expanded numeric data types
 for processing higher precision real (and integer) numbers. For reals, this
 includes support for single and double precision real numbers according to
 the IEEE floating-point standard, as well as single and double precision
 decimal-format numbers.

 Standard Pascal provides a type REAL. MS-Pascal provides three real
 types: REAL, REAL4, and REAL8. However, the type REAL is always identical
 to either REAL4 or REAL8. The choice is made with a metacommand, $real:n,
 where n is either 4 or 8. {$real:8} has the same effect as TYPE REAL =
 REAL8. The default type for REAL is normally REAL4, but may be changed.
 See Appendix B, "Version Specifics," in the Microsoft Pascal Compiler
 User's Guide for details.

 Any or all of these real number forms may be used in a single program.
 However, programs that use REAL4 and REAL8 will not be portable.

 The REAL4 type is in 32-bit IEEE format, and the REAL8 type is in 64-
 bit IEEE format. The IEEE standard format is as follows:

      REAL4       Sign bit, 8-bit binary exponent with
                  bias of 127, 23-bit mantissa

      REAL8       Sign bit, 11-bit binary exponent with
                  bias of 1023, 52-bit mantissa

 In both cases the mantissa has a "hidden" most significant bit (always one)
 and represents a number greater than or equal to 1.0 but less than 2.0. An
 exponent of zero means a value of zero, and the maximum exponent means a
 value called NAN ("Not A Number"). Bytes are in "reverse" order; the
 lowest addressed byte is the least significant mantissa byte.

 The REAL4 numeric range is barely seven significant digits (24 bits),
 with an exponent range of E-38 to E+38. The REAL8 numeric range includes
 over fifteen significant digits (53 bits), with an exponent range of E-306
 to E+306 (a very large number!).

 The exponent character can be "D" or "d" as well as "E" or "e", so a
 number like 12.34d56 is permitted. This minor extension provides
 compatibility with other Microsoft languages. However, the D or d exponent
 character does not indicate double precision (as it does in FORTRAN), since
 this would imply that numbers with E or e exponent characters are single
 precision.

 REAL literals in MS-Pascal are converted first to REAL8 format and
 then to REAL4 as necessary (for example, to be passed as a CONST parameter
 or to initialize a variable in a VALUE section). If you need actual REAL4
 constants, you must declare them as REAL4 variables (perhaps adding the
 READONLY attribute) and assign them a constant in a VALUE section.

 Both REAL4 and REAL8 values are passed to intrinsic functions as
 reference (CONSTS) parameters, rather than as value parameters. The
 compiler accepts REAL expressions as CONSTS parameters;  it will evaluate
 the expression, assign the result to a stack temporary, and pass the
 address of the temporary, which is usually more efficient than passing the
 value itself (especially in the REAL8 case).

 Functions that return REAL values use the long return method; that is,
 the caller passes an additional, hidden, offset address of a stack
 temporary which will receive the result. This applies to all functions
 returning REAL4 or REAL8 values, both user-defined and intrinsic. See
 Section 12.2, "Boolean Expressions," for a description of REAL comparisons
 that produce an unordered result.

 The MS-Pascal runtime libraries provide additional REAL functions
 to support Microsoft FORTRAN. These functions are available in MS-Pascal,
 but are not predeclared. See Chapter 15, "Available Procedures and
 Functions," for further information on the functions available and how to
 use them.

 Base ten representation of REAL data is supported by Microsoft Pascal
 using a floating-point format. It consists of 6 (single) and 14 (double)
 binary coded decimal digits packed two to a byte. (If the exponent byte is
 zero, the number is zero). For information on the allowable ranges for
 single and double precision numbers, see Section 9.2, "Internal
 Representations of Data Types," in the Microsoft Pascal Compiler User's
 Guide.


 6.3  INTEGER4


 Like INTEGER and WORD values, INTEGER4 values are a subset of the whole
 numbers. INTEGER4 values range from -MAXLONG to MAXLONG. MAXLONG is a
 predeclared constant with the value of 2,147,483,647 (i.e., 2^31 - 1). The
 value -2,147,487,648 (i.e., -2^31) is not a valid INTEGER4.

 Unlike INTEGER and WORD, the INTEGER4 type is not considered an
 ordinal type. There are no INTEGER4 subranges and INTEGER4 cannot be an
 array index or the base type of a set. Also, INTEGER4 values cannot be
 used to control FOR and CASE statements.

 INTEGER4 is currently an extended numeric type, like REAL. Values of
 type INTEGER or WORD in an expression change automatically to INTEGER4 if
 the expression requires an intermediate value that is out of the range of
 either INTEGER or WORD. Values of type INTEGER4 do not change to REAL in
 an expression; you must explicitly use the FLOATLONG function to make the
 conversion.



 Chapter 7  Arrays, Records, and Sets

 

 7.1  Arrays

 7.2  Super Arrays

       7.2.1  STRINGs

       7.2.2  LSTRINGs

       7.2.3  Using STRINGs and LSTRINGs

 7.3  Records

       7.3.1  Variant Records

       7.3.2  Explicit Field Offsets

 7.4  Sets



 A structured type is composed of other types. The components of
 structured types are either simple types or other structured types. A
 structured type is characterized by the types of its components and by its
 structuring method. In Microsoft Pascal, a structured type can occupy up to
 65534 bytes of memory.

 The structured types in MS-Pascal are the following:

      ARRAY <range> OF <type>
      SUPER ARRAY <range> OF <type>
        STRING  (n)
        LSTRING (n)
      RECORD
      SET OF <base-type>
      FILE OF <type>

 Because components of structures can be structured types themselves, you
 may have, for example, an array of arrays, a file of records containing
 sets, or a record containing a file and another record. This is an example
 of the data typing flexibility that provides Pascal with much of its
 linguistic power as a computing language.

 The remainder of this chapter discusses arrays, records, and sets.
 See Chapter 8, "Files," for a discussion of files.


 7.1  Arrays


 An array type is a structure that consists of a fixed number of
 components. All of the components are of the same type (called the
 "component type").

 The elements of the array are designated by indices, which are values
 of the "index type" of the array. The index type must be an ordinal type:
 BOOLEAN, CHAR, INTEGER, WORD, subrange, or enumerated.

 Arrays in Pascal are one-dimensional, but since the component type can
 also be an array, n-dimensional arrays are supported as well.

 Examples of type declarations for arrays:

      TYPE
      INT_ARRAY : ARRAY [1..10] OF INTEGER;
      ARRAY_2D : ARRAY [0..7] OF ARRAY [0..8] OF 0..9;
      MORAL_RAY : ARRAY [PEOPLE] OF (GOOD, EVIL)

 In the last declaration, PEOPLE is a subrange type, while GOOD and EVIL are
 enumerated constants.

 A short-hand notation available for n-dimensional arrays makes the
 following statement the same as the second example in the preceding
 paragraph:

      ARRAY_2D : ARRAY [0..7, 0..8] OF 0..9;

 After declaring these arrays, you could assign to components of the
 arrays with statements such as these:

      INT_ARRAY [10] := 1234;
      ARRAY_2D [0,99] := 9;
      MORAL_RAY [Machiavelli] := EVIL;

 All of an n-dimensional PACKED array is packed; therefore these statements
 are equivalent:

      PACKED ARRAY [1..2, 3..4] OF REAL
      PACKED ARRAY [1..2] OF PACKED ARRAY [3..4] OF REAL

 See Chapter 9, "Reference and Other Types," for a discussion of packed
 types.


 7.2  Super Arrays


 A super array is an example of an MS-Pascal "super type."  A super type
 is like a set of types or like a function that returns a type. Super types
 in general, and super arrays in particular, are features of MS-Pascal.

 The super array type has several important uses. You may use it for
 any of the following purposes:

     1.  To process strings. Both STRING and LSTRING are predeclared super
         array types. The LSTRING type handles variable length strings.
         STRING handles fixed-length strings and strings more than 255
         characters long.

     2.  To dynamically allocate arrays of varying sizes. Otherwise such
         arrays would need a maximum possible size allocation.

     3.  As the formal parameter type in a procedure or function. Such a
         declaration makes the procedure or function usable for a set or
         class of types, rather than for just a single fixed-length type.

 A super type identifier specifies the set of types represented by the
 super type. A later type declaration may declare a normal type identifier
 as a type "derived" from that class of types. This derived type is like any
 other type.

 A super array type declaration is an array type declaration prefixed
 with the keyword SUPER. Every array upper bound is replaced with an
 asterisk, as shown:

      TYPE VECTOR = SUPER ARRAY [1..*] OF REAL;

 Following the preceding type declaration, you could declare the following
 variables:

      VAR ROW : VECTOR (10);
          COL : VECTOR (30);
          ROWP : ^VECTOR;

 In this example, VECTOR is a super array type identifier. VECTOR (10) and
 VECTOR (30) are type designators denoting "derived types." ROW and COL are
 variables of types derived from VECTOR. ROWP is a pointer to the super
 array type VECTOR.

 Although the general concept of super types allows other "types of
 types," such as super subranges and super sets (in addition to super
 arrays), super types currently allow only an array type with parametric
 upper bounds. A super type is a class of types and not a specific type.
 Thus, in the VAR section of a program, procedure, or function, you cannot
 declare the variables to be of a super type; you must declare them as
 variables of a type derived from the super type.

 However, a formal reference parameter in a procedure or function can
 be given a super type: this allows the routine to operate on any of the
 possible derived types. (This kind of parameter is called a "conformant
 array" in other Pascals.)

 A pointer referent type can also be given a super type. This allows a
 pointer to refer to any of the possible derived types. A pointer referent
 to a super type allows "dynamic arrays." These arrays are allocated on the
 heap by passing their upper bound to the procedure NEW. See Chapter 9,
 "Reference and Other Types," for a discussion of pointer types and dynamic
 allocation. See Chapter 15, "Available Procedures and Functions," for a
 description of the procedure NEW.

 Example using the NEW procedure for dynamic allocation:

      VAR STR_CRT : ^SUPER PACKED ARRAY [1..*] OF CHAR;
            VEC_CRT : ^SUPER ARRAY [0..*, 0..*] OF REAL;
              .
              .
            NEW (STR_CRT, 12);
            NEW (VEC_CRT, 9, 99);

 An actual parameter in a procedure or function can be of a super type
 rather than a derived type, but only if the parameter is a reference
 parameter or pointer referent. (These are the only kinds of variables that
 can be of a super rather than a derived type.)

 Example of super arrays:


      TYPE VECTOR = SUPER ARRAY [1..*] OF REAL;
      {"VECTOR" is the super array type identifier.}

      VAR X : VECTOR (12); Y : VECTOR (24); Z : VECTOR (36);
      {X, Y, and Z are types derived from VECTOR.}

      {Below, SUM accepts variables of all types}
      {derived from the super type VECTOR.}
      FUNCTION SUM (VAR V : VECTOR) : REAL;
      {V is the formal reference parameter of the}
      {super type VECTOR.}

      VAR S : REAL; I : INTEGER;
      BEGIN
        S := 0;
        FOR I := 1 TO UPPER (V) DO S := S + V [I];
        SUM := S
      END;

      BEGIN
        .
        .
        TOTAL := SUM (X) + SUM (Y) + SUM (Z);
        .
        .
      END

 The normal type rules for components of a super array type and for
 type designators that use a super array type allow components to be
 assigned, compared, and passed as parameters.

 The UPPER function returns the actual upper bound of a super array
 parameter or referent. The maximum upper bound of a type derived from a
 super array type is limited to the maximum value of the index type implied
 by the lower bound (e.g., MAXINT, MAXWORD). Two super array types are
 predeclared, STRING and LSTRING. The compiler directly supports STRING and
 LSTRING types in the following ways:

     1.  LSTRING and STRING assignment

     2.  LSTRING and STRING comparison

     3.  LSTRING and STRING READs

     4.  access to the length of a STRING with the UPPER function

     5.  access to maximum length of an LSTRING with the UPPER function

     6.  access to LSTRING length with STR.LEN and STR[0]

 These subjects are discussed in Section 7.2.3, "Using STRINGs AND
 LSTRINGs."


 7.2.1  STRINGs


 STRINGs are predeclared super arrays of characters:

      TYPE STRING  = SUPER PACKED ARRAY [1..*] OF CHAR;

 A string literal such as 'abcdefg' automatically has the type STRING (n).
 The size of the array 'abcdefg' is 7; thus, the constant is of the STRING
 derived type, STRING (7).

 Standard Pascal calls any packed array of characters with a lower
 bound of one a "string" and permits a few special operations on this type
 (such as comparison and writing) that you cannot do with other arrays.

 In MS-Pascal, the super array notation STRING (n) is identical to
 PACKED ARRAY [1..n] OF CHAR (n may range from 1 to MAXINT). There is no
 default for n, as in some other Pascals, since STRING means the super array
 type itself and not a string with a default length.

 The identifier STRING is for a super array, so you can only use it as
 a formal reference parameter type or pointer referent type. The other
 super array restrictions apply: You may not compare such a parameter or
 dereferenced pointer or assign it as a whole.

 Any variable (or constant) with the super array type STRING, or one of
 the types CHAR or STRING (n) or PACKED ARRAY [1..n] OF CHAR, can be passed
 to a formal reference parameter of super array type STRING. Furthermore, a
 variable of type LSTRING or LSTRING (n) can also be passed to a formal
 reference parameter of type STRING. For a discussion of STRING as a formal
 reference parameter, see Section 7.2.3, "Using STRINGs and LSTRINGs."

 Standard Pascal supports the assigning, comparing, and writing of
 STRINGs. The extend level permits reading STRINGs, including the super
 array type STRING and a derived type STRING (n). Reading a STRING causes
 input of characters until the end of a line or the end of the STRING is
 reached. If the end of the line is reached first, the rest of the STRING is
 filled with blanks. Writing a string writes all of its characters.

 The customary Pascal type compatibility rules are relaxed for STRINGs.
 Any two variables or constants with the type PACKED ARRAY [1..n] OF CHAR or
 the type STRING (n) can be compared or assigned if the lengths are equal.
 However, since the length of a STRING super array type may vary,
 comparisons and assignments are not allowed.

 Example of an illegal STRING assignment:

      PROCEDURE CANNOT_DO (VAR S : STRING);
      VAR STR : STRING (10);
      BEGIN
        STR := S
        {This assignment is illegal because}
        {the length of S may vary.}
      END;

 The PACKED prefix in the declaration PACKED ARRAY [1..n] OF CHAR, as
 defined in the ISO standard, normally implies that a component cannot be
 passed as a reference parameter. In MS-Pascal, this restriction does not
 apply.

 To keep conformance to the ISO standard, this passing of the CHAR
 component of a STRING as a reference parameter is defined as an "error not
 caught." Also, the index type of a string is officially INTEGER, but WORD
 type values can also be used to index a STRING. Many string-processing
 applications are expected to take advantage of the LSTRING type, described
 in Section 7.2.2, "LSTRINGs."

 A number of intrinsic procedures and functions for strings are
 discussed in Chapter 15, "Available Procedures and Functions." Many of the
 procedures and functions described work on STRINGs; some apply only to
 LSTRINGs.


 7.2.2  LSTRINGs


 The LSTRING feature in MS-Pascal allows variable-length strings.
 LSTRING (n) is predeclared as:

      TYPE LSTRING = SUPER PACKED ARRAY [0..*] OF CHAR

 However, a variable with the explicit type PACKED ARRAY [0..n] OF CHAR is
 not "identical" to the type LSTRING (n) even though they are structurally
 the same. There is no default for n; the range of n is from zero to 255.
 Characters in an LSTRING can be accessed with the usual array notation.

 Internally, LSTRINGs contain a length (L), followed by a string of
 characters. The length is contained in element zero of the LSTRING and can
 vary from 0 to the upper bound. The length of an LSTRING variable T can be
 accessed as T[0] with type CHAR, or as T.LEN with type BYTE. String
 constants of type CHAR or STRING (n) are changed automatically to type
 LSTRING.

 The predeclared constant NULL is the empty string, LSTRING (0).
 NULL is the only constant with type LSTRING; there is no way to define
 other LSTRING constants. As with STRINGs, a CHAR component of an LSTRING
 can be passed as a reference parameter, and  WORD and INTEGER values can be
 used to index an LSTRING.

 Several operations work differently on LSTRINGs than on STRINGs.
 Any LSTRING can be assigned to any other LSTRING, so long as the current
 length of the right side is not greater than the maximum length of the left
 side. Similarly, an LSTRING can be passed as a value parameter to a
 procedure or function, so long as the current length of the actual
 parameter is not greater than the maximum length specified by the formal
 parameter. If the range checking switch is on, the compiler checks the
 assignment of LSTRINGs and the passing of LSTRING (n) parameters. The
 actual number of bytes assigned or passed is the minimum of the upper
 bounds of the LSTRINGs.

 Neither side in an LSTRING assignment can be a parameter of the super
 array type LSTRING; both must be types derived from it.

 Examples of LSTRING assignments:

      {Declaring the variables}
      VAR A : LSTRING (19);
          B : LSTRING (14);
          C : LSTRING (6);
            .
            .
      {Assigning the variables}
      A := '19 character string';
      B := '14 characters';
      C := 'shorty';
      A := B;
      {This is legal, since the length of B}
      {is less than the maximum length of A.}
      C := A;
      {This is illegal, since length of A}
      {is greater than the maximum length of C.}

 You may compare any two LSTRINGs, including super array type LSTRINGs (the
 only super array type comparison allowed). Reading an LSTRING variable
 causes input of characters, until the end of the current line or the end of
 the LSTRING, and sets the length to the number of characters read. Writing
 from an LSTRING writes the current length string.


 7.2.3  Using STRINGs and LSTRINGs


 This section describes the STRING and LSTRING operations directly supported
 by the compiler. An annotated program at the end of this section
 illustrates the use of STRINGs and LSTRINGs in context.

 See also Chapter 15, "Available Procedures and Functions," for
 descriptions of the following string procedures and functions:

      CONCAT      INSERT
      COPYLST     POSITN
      COPYSTR     SCANEQ
      DELETE      SCANNE

 At the system level of MS-Pascal, the procedures FILLC, FILLSC, MOVEL,
 MOVESL, MOVER, and MOVESR also operate on strings.

 MS-Pascal supports STRINGs and LSTRINGs directly in the following
 ways:

  1.  Assignment

      You may assign any LSTRING value to any LSTRING variable, as long
      as the maximum length of the target variable is greater than or
      equal to thecurrent length of the source value and neither is the
      super array type LSTRING. If the maximum length of the target is
      less than the current length of the source, only the target length
      is assigned, and a runtime error occurs if the range checking
      switch is on. You may assign a STRING value to a STRING variable,
      as long as the length of both sides is the same and neither side is
      the super array type STRING. Passing either STRING or LSTRING as a
      value parameter is much like making an assignment.

  2.  Comparison

      The LSTRING operators <  <=  >  >=  <>  = use the length byte for
      string comparisons; the operands may be of different lengths. Two
      strings must be the same length to be considered equal. If two strings
      of different lengths are equal up to the length of the shorter one,
      the shorter is considered less than the longer one. The operands can
      be of the super array type LSTRING. For STRINGs, the same relational
      operators are available, but the lengths must be the same and operands
      of the super array type STRINGs are not allowed.

  3.  READs and WRITEs

      READ LSTRING reads until the LSTRING is filled or until the end-of-
      line is found. The current length is set to the number of characters
      read. WRITE LSTRING uses the current length. See also READSET
      (described in Chapter 16, "File-Oriented Procedures and Functions"),
      which reads into an LSTRING as long as input characters are in a given
      SET OF CHAR. READ STRING pads with spaces if the line is shorter than
      the STRING. WRITE STRING writes all the characters in the string.
      Both READ and WRITE permit the super array types STRING and LSTRING,
      as well as their derived types.


  4.  Length access

      You can access the current length of an LSTRING variable T with
      T.LEN, which is of type BYTE, or with T[0], which is of type CHAR.
      This notation can assign a new length, as well as determine the
      current length. The UPPER function will find the maximum length of an
      LSTRING or the length of a STRING. This is especially useful for
      finding the upper bound of a super array reference parameter or
      pointer referent.

 You cannot assign or compare mixed STRINGs and LSTRINGs, unless the
 STRING is constant. You can assign STRINGs to LSTRINGs, or vice versa,
 with one of the move routines or with the COPYSTR and COPYLST procedures.
 Since constants of type STRING or CHAR change automatically to type LSTRING
 if necessary, LSTRING constants are considered normal STRING constants.
 NULL (the zero length LSTRING) is the only explicit LSTRING constant.

 In the sample program at the end of this section, all STRING
 parameters (CONST or VAR) may take either a STRING or an LSTRING; all
 LSTRING parameters are VAR LSTRING and must take an LSTRING variable.

 A "special transformation" lets you pass an actual LSTRING parameter
 to a formal reference parameter of type STRING. The length of the formal
 STRING is the actual length of the LSTRING. Therefore, if LSTR (in the
 following example) is of type LSTRING (n) or LSTRING, it can be passed to a
 procedure or function with a formal reference parameter of type STRING:

      VAR LSTR : LSTRING (10);
        .
        .
      PROCEDURE TIE_STRING (VAR STR : STRING);
        .
        .
      TIE_STRING (LSTR);

 In this case, UPPER (STR) is equivalent to LSTR.LEN.

 Procedures and functions with reference parameters of super type
 STRING can operate equally well on STRINGs and LSTRINGs. The only reason to
 declare a parameter of type LSTRING is when the length must be changed.
 Normally, an LSTRING is either a VAR or a VARS parameter in a procedure or
 function, since a CONST or CONSTS parameter of type LSTRING cannot be
 changed.

 Example of a program that uses STRINGs and LSTRINGs:

      PROGRAM STRING_SAMPLE;

      PROCEDURE STRING_PROC  (CONST S : STRING);  BEGIN END;
      PROCEDURE LSTRING_PROC (CONST S : LSTRING);  BEGIN END;

      VAR
        CHR1VAR : CHAR;
        STR5VAR : STRING (5);
        LST5VAR : LSTRING (5);
        LST9VAR : LSTRING (9);
        STR4VAR : PACKED ARRAY [1..4] OF CHAR;
        STR6VAR : PACKED ARRAY [1..6] OF CHAR;

      BEGIN

      {Look at all the kinds of strings a}
      {CONST STRING parameter takes.}
      STRING_PROC ('A');
      {Character constant is OK.}
      STRING_PROC (CHR1VAR);
      {Character variable is OK.}
      STRING_PROC ('STRING');
      {STRING constant is OK.}
      STRING_PROC (STR5VAR);
      {STRING variable is OK.}
      STRING_PROC (LST5VAR);
      {LSTRING variable is OK.}

      {However, a CONST LSTRING parameter cannot take}
      {non-LSTRING variables.}
      LSTRING_PROC ('A');
      {Character constant is OK.}
      LSTRING_PROC (CHR1VAR);
      {Character variable is not OK!}
      LSTRING_PROC ('STRING');
      {STRING constant is OK.}
      LSTRING_PROC (STR5VAR);
      {STRING variable is not OK!}
      LSTRING_PROC (LST5VAR);
      {LSTRING variable is OK.}

      {Assignments to a STRING variable are limited}
      {to the same type.}
      STR5VAR := 'A';
      {Character constant is not OK!}
      STR5VAR := CHR1VAR;
      {Character variable is not OK!}
      STR5VAR := 'TINY';
      {STRING constant is too small.}
      STR5VAR := 'RIGHT';
      {Both sides have five characters; OK.}
      STR5VAR := 'longer';
      {Not OK; STRING constant is too large.}
      STR5VAR := LST5VAR;
      {Not OK; you cannot assign LSTRINGs to STRINGs.}
      COPYSTR (LST5VAR, STR5VAR);
      {COPYSTR is an intrinsic procedure.}
      STR5VAR := STR4VAR;
      {Not OK; STRING variable is too small.}
      COPYSTR (STR4VAR, STR5VAR);
      {COPYSTR is OK; padding of space in STR5VAR[5].}
      STR5VAR := STR5VAR;
      {OK; both sides have five characters.}
      STR5VAR := STR6VAR;
      {Not OK; STRING variable is too large.}

      {Assignments to an LSTRING variable, however,}
      {are more flexible.}
      LST5VAR := 'A';
      {Character constant is OK.}
      LST5VAR := CHR1VAR;
      {Character variable is not OK!}
      LST5VAR := 'TINY';
      {Smaller STRING constant is OK.}
      LST5VAR := 'RIGHT';
      {Same length STRING constant is OK.}
      LST5VAR := 'LONGER';
      {This gives an error at runtime only; OK for now.}
      LST5VAR := LST9VAR;
      {This may give an error at runtime; OK for now.}
      LST9VAR := LST5VAR;
      {This isn't even checked at runtime; always OK.}
      LST5VAR := STR5VAR;
      {Not OK; you cannot assign a STRING variable to an}
      {LSTRING variable.}
      COPYLST (STR5VAR, LST5VAR)
      {This is the way to copy a STRING variable}
      {to an LSTRING.}

 END.


 7.3  Records


 A record structure acts as a template for conceptually related data of
 different types. The record type itself is a structure consisting of a
 fixed number of components, usually of different types.

 Each component of a record type is called a field. The definition of a
 record type specifies the type and an identifier for each field within the
 record. Because the scope of these "field identifiers" is the record
 definition itself, they must be unique within the declaration. The field
 values associated with field identifiers are accessible with record
 notation or with the WITH statement.

 For example, you could declare the following record type:

      TYPE LP = RECORD
                TITLE : LSTRING (100);
                ARTIST : LSTRING (100);
                PLASTIC : ARRAY
                  [1..SONG_NUMBER] OF SONG_TITLE
                END

 You could then declare a variable of the type LP, as follows:

      VAR BEATLES_1 : LP;

 Finally, you could access a component of the record with either field
 notation or the WITH statement (note the period separating field
 identifiers):

      BEATLES_1.TITLE := 'Meet The Beatles';
      WITH BEATLES_1 DO
         PLASTIC[1] := 'I Wanna Hold Your Hand'


 7.3.1  Variant Records


 A record may have several "variants," in which case a certain field
 called the "tag field" indicates which variant to use. The tag field
 may or may not have an identifier and storage in the record. Some
 operations, such as the NEW and DISPOSE procedures and the SIZEOF function,
 can specify a tag value even if the tag is not stored as part of the
 record.

 Examples of variant records:

      TYPE OBJECT = RECORD
             X, Y : REAL;
             CASE S : SHAPE OF
               SQUARE : (SIZE, ANGLE : REAL);
               CIRCLE : (DIAMETER : REAL)
          END;

          FOO = RECORD
            CASE BOOLEAN OF
              TRUE : (I, J : INTEGER);
              FALSE : (CASE COLOR OF
                     BLUE : (X : REAL);
                     RED : (Y : INTEGER4))
          END;

 Only one variant part per record is allowed; it must be the last field of
 the record. However, this variant part can also have a variant (and so on,
 to any level). All field identifiers in a given record type must be
 unique, even in different variants. For example, after declaring the
 record types above, you could create and then assign to the variables shown
 in the following example:

      VAR O, P : OBJECT;
          F, G : FOO;

      BEGIN
        O.DIAMETER := 12.34;  {CASE of CIRCLE}
        P.SIZE := 1.2;        {CASE of SQUARE}
        F.I := 1; F.J := 2;   {CASE of TRUE}
        G.X := 123.45;       {CASE of FALSE and BLUE}
        G.Y := 678999         {CASE of FALSE and RED;}
                              {this overwrites G.X.}
      END;

 The latest ISO standard requires every possible tag field value to select
 some variant. Therefore, it is illegal to include CASE INTEGER OF and omit
 a variant for every possible INTEGER value. However, such an omission is an
 error not caught in MS-Pascal.

 MS-Pascal supports the use of full CASE constant options in the variant
 clause; that is, a list of constants can define a case. At the
 extend level, subranges and the OTHERWISE statement can also define a case.
 If used, OTHERWISE applies to the last variant in the list and is not
 followed by a colon. You can also declare an empty variant, such as
 POINT:() or OTHERWISE (). You can even declare an entirely empty
 record type, although the compiler issues a warning whenever the record
 is used.

 The ISO standard defines a number of errors that relate to variant
 records; these errors may not be caught in MS-Pascal, even if the tag-
 checking switch is on. (The tag-checking switch generates code each time a
 variant field is used, to check that the tag value is correct.)  In the
 record type declaration of OBJECT (in the previous example), any use of
 SIZE generates a check that S = SQUARE. However, in the case of FOO, uses
 of "I" cannot be checked because MS-Pascal does not allocate the BOOLEAN
 tag field.

 The ISO standard further declares that when a "change of variant"
 occurs (such as when a new tag value is assigned), all the variant fields
 become undefined. However, MS-Pascal does not set the fields to an
 uninitialized value when a new tag is assigned. Therefore, using a variant
 field with an undefined value is an error not caught in MS-Pascal.

 Nor does MS-Pascal enforce various restrictions on a record variable
 allocated on the heap with the long form of the NEW procedure. See Chapter
 15, "Available Procedures and Functions," for details. However, MS-Pascal
 does check an assignment to such a "short record" to see that only the
 short record itself is modified in the heap.

 A record allocated with the long form of NEW may be released using the
 short form of DISPOSE with no ill effects (this is an ISO error not caught
 in MS-Pascal). It is also an error not caught in MS-Pascal to DISPOSE of a
 record passed as a reference parameter or used by an active WITH statement.

 Variant records interact with MS-Pascal features in two ways:

     1.  Declaring a variant that contains a file is not safe; any change to
         the file's data using a field in another variant may lead to I/O
         errors, even if the file is closed. In the following example, any
         use of R will lead to errors in F:

              RECORD CASE BOOLEAN OF
                  TRUE : (F : FILE OF REAL);
                  FALSE : (R : ARRAY [1..100] OF REAL)
                  END;

     2.  Giving initial data to several overlapping variants in a variable
         in a VALUE section could have unpredictable results. In the
         following example, the initial value of LAP is uncertain:

              VAR LAP : RECORD CASE BOOLEAN OF
                  TRUE : (I : INTEGER4);
                  FALSE : (R : REAL)
                  END;
              VALUE LAP.I := 10; LAP.R := 1.5;

 MS-Pascal generates a warning message if you attempt either of these
 operations.


 7.3.2  Explicit Field Offsets


 MS-Pascal lets you assign explicit byte offsets to the fields in a
 record. This system level feature can be useful for interfacing to
 software in other languages, since control block formats may not conform to
 the usual MS-Pascal field allocation method. However, because it also
 permits unsafe operations, such as overlapping fields and word values at
 odd byte boundaries, it is not recommended unless the interface is
 necessary.

 Example showing assignment of explicit byte offsets:

      TYPE CPM = RECORD
                   NDRIVE [00] : BYTE;
                   FILENM [01] : STRING (8);
                   FILEXT [09] : STRING (3);
                   EXTENT [12] : BYTE;
                   CPMRES [13] : STRING (20);
                   RECNUM [33] : WORD;
                   RECOVF [35] : BYTE
                 END;

         OVERLAP = RECORD
                   BYTEAR [00] : ARRAY [0..7] OF BYTE;
                   WORDAR [00] : ARRAY [0..3] OF WORD;
                   BITSAR [00] : SET OF 0..63
                 END;

 As may be seen in the example, the offset is enclosed in brackets; this is
 similar to attribute notation. The number is the byte offset to the start
 of the field. Some target machines may not permit accessing a 16-bit value
 at an odd address, but the MS-Pascal Compiler doesn't catch this as an
 error.

 If you give any field an offset, give offsets to all fields. For any
 offset that you omit, the compiler picks an arbitrary value. Although the
 compiler will process a declaration that includes both offsets and variant
 fields, you should use only one or the other in a given program.

 Although you can completely control field overlap with explicit
 offsets, variants provide the long forms of the procedures NEW, DISPOSE,
 and SIZEOF. If you want to allocate different length records, use the
 RETYPE and GETHQQ procedures, instead of variants and the long form of NEW.
 For example:

      CPMPV := RETYPE (CPMP, GETHQQ (36));

 The compiler does support structured constants for record types with
 explicit offsets. Internally, odd length fields greater than one are
 rounded to the next even length. For example:

      ODDR = RECORD
               F1[00] : STRING (3);
               F2[03] : CHAR
             END;

 In this example, field F1 is four bytes long, so an assignment to F1
 overwrites F2. In such a record, all odd length fields must be assigned
 first.


 7.4  Sets


 A set type defines the range of values that a set may assume. This
 range of assumable values is the "power set" of the base type you specify
 in the type definition. The power set is the set of all possible sets that
 could be composed from an ordinal base type. The null set, [], is a member
 of every set.

 Suppose you declare the following set types:

      TYPE HUES = SET OF COLOR;
           CAPS = SET OF 'A'..'Z';
           MATTER = SET OF (ANIMAL, VEGETABLE, MINERAL);

 Then you declare variables like the following:

      VAR FLAG : HUES;
          VOWELS : CAPS;
          LIVE : MATTER;

 Finally, you could assign these set variables:

      FLAG := [RED, WHITE, BLUE];
      VOWELS := ['A', 'E', 'I', 'O', 'U'];
      LIVE := [ANIMAL, VEGETABLE];

 The set elements must be enclosed in brackets. This practice differs from
 the use of parentheses to enclose the base enumerated type in a set type
 declaration.

 Set operations are implemented directly by generated in-line code or
 by routines in the set unit. See Chapter 12, "Expressions," for a complete
 discussion of operations on sets.

 The ORD value of the base type can range from 0 to 255. Thus, SET OF
 CHAR is legal, but SET OF 1942..1984 is not.

 Sets whose maximum ORD value is 15 (i.e., sets that fit into a WORD)
 are usually more efficient than larger ones. Also, if the range checking
 switch is on, passing a set as a value parameter invokes a runtime
 compatibility check, unless the formal and actual sets have the same type.

 Sets provide a clear and efficient way of giving several qualities or
 attributes to an object. In another language, you might assign each quality
 a power of two:

      READY = 1
      GETSET = 2
      ACTIVE = 4
      DONE = 8

 You might then assign the qualities with a statement like this:

      X := (READY + ACTIVE)

 and then test them using OR and AND as bitwise operators with a statement
 like:

      IF ((X AND ACTIVE) <> 0) THEN WRITELN ('GO FISH')

 The equivalent declaration in MS-Pascal might be:

      QUALITIES = SET OF (READY, GETSET, ACTIVE, DONE);

 You could then assign the qualities with X := [ GETSET, ACTIVE] and test
 them with the following operations:

      IN          tests a bit
      +           sets a bit
      -           clears a bit

 For  example, an appropriate construction might be:

      IF ACTIVE IN X THEN WRITELN ('GO FISH')

 You can also use SET OF 0..15 to test and set the bits in a WORD. Using
 WORDs both as a set of bits and as the WORD type requires giving two types
 to the word, with a variant record, the RETYPE function, or an address
 type.

 The bits in a set are assigned starting with the most significant bit
 in the lowest addressed byte. Thus, on a byte-swapped machine, the set [0,
 7, 8, 15] has the WORD value #80 + #01 + #8000 + #0100.



 Chapter 8  Files

 

 8.1  Declaring Files

 8.2  The Buffer

 8.3  File Structures

       8.3.1  BINARY Structure Files

       8.3.2  ASCII Structure Files

 8.4  File Access Modes

       8.4.1  TERMINAL Mode Files

       8.4.2  SEQUENTIAL Mode Files

       8.4.3  DIRECT Mode Files

 8.5  The Predeclared Files: INPUT and OUTPUT

 8.6  File I/O: Extend Level

 8.7  File I/O: System Level



 A file is a structure that consists of a sequence of components, all of
 the same type. It is through files that Microsoft Pascal interfaces with a
 given operating system. Therefore, you must understand the FILE type in
 order to perform input to and output from a program.


 8.1  Declaring Files


 As with any other type, you must declare a file variable in order to use
 it. However, the number of components in a file is not fixed by declaring
 a FILE type.

 Examples of FILE declarations:

      TYPE F1 = FILE OF COLOR;
           F2 = FILE OF CHAR;
           F3 = TEXT;

 Conceptually, a file is simply another data type, like an array, but with
 no bounds and with only one component accessible at a time. However, a
 file is usually associated with one of the following:

     1.  disk files

     2.  terminals

     3.  printers

     4.  other input and output devices

 This implies the following restriction in MS-Pascal: a FILE OF FILE is
 illegal, directly or indirectly. Other structures, such as a FILE OF ARRAYs
 or an ARRAY OF FILEs, are permitted.

 Most Pascal implementations connect file variables to the data files
 of the operating system. MS-Pascal always uses the target operating system
 to access files but does not impose additional formatting or structure on
 operating system files.

 MS-Pascal supports normal statically allocated files, files as local
 variables (allocated on the stack), and files as pointer referents
 (allocated on the heap). Except for files in super arrays, the compiler
 generates code to initialize a file when it is allocated and to CLOSE a
 file when it is deallocated.

 This initialization call occurs automatically in most cases. However,
 a file declared in a module or uninitialized unit's interface will only get
 its initialization call if you call the module or unit identifier as a
 procedure. File declarations in such cases get the following compiler
 warning:

      Contains file initialize module

 Only a file in an interface of an uninitialized unit does not generate this
 warning.

 MS-Pascal sets up the standard files, INPUT and OUTPUT (discussed in
 Section 8.5, "The Predeclared Files: INPUT and OUTPUT"). In standard
 Pascal, files must be given in the program header, and when you run your
 program, the runtime system prompts you for filenames. At the extend
 level, you may use the ASSIGN and READFN procedures to give explicit
 operating system filenames to files not included in the program header.

 Files in record variants or super array types are not recommended; if
 you use them, the compiler issues a warning. A file variable cannot be
 assigned, compared, or passed by value: It can only be declared and passed
 as a reference parameter.

 At the extend level, you may indicate a file's access method or other
 characteristics by specifying the mode of the file. The mode is a value of
 the predeclared enumerated type FILEMODES. The modes available normally
 include the three base modes, SEQUENTIAL, TERMINAL, and DIRECT. All files,
 except INPUT and OUTPUT, are given SEQUENTIAL mode by default. INPUT and
 OUTPUT are given the default mode TERMINAL.


 8.2  The Buffer


 Every file F has an associated buffer variable F^. A buffer variable
 and its associated file might look like this:

      +---+---+---+---+---+---+
      | a | b | c | d | e |   |
      +---+---+---+---+---+---+
                        ^
                        | Pointer to current component

                      +---+
                      | e |    Buffer variable
                      +---+

 The procedures GET and PUT use this buffer variable to READ from and
 WRITE to files. GET copies the current component of the file to the buffer
 variable. PUT does the opposite; that is, PUT copies the value of the
 buffer variable to the current component.

 The buffer variable can be referenced (i.e., its value fetched or
 stored) like any other MS-Pascal variable. This allows execution of
 assignments like the following:

      F^ := 'z'
      C := F^

 A file buffer variable can be passed as a reference parameter to a
 procedure or function or used as a record in a WITH statement. However, the
 file buffer variable may not be updated correctly if the file position
 changes within the procedure, function, or WITH statement. The compiler
 issues a warning message to alert you to this possibility.

 For example, the following use of a file buffer variable would generate
 a warning at compile time:

      VAR A : TEXT;
      PROCEDURE CHAR_PROC (VAR X : CHAR);
        .
        .
      CHAR_PROC (A^);
      {Warning issued here}

 Two special internal mechanisms in MS-Pascal, lazy evaluation and
 concurrent I/O, allow, respectively, interactive terminal input in a
 natural way and overlapped I/O along with program execution. Lazy
 evaluation is applied to all ASCII structured files and is necessary
 for natural terminal input. Concurrent I/O is applied to all BINARY
 structured files and is necessary for some operating systems that
 support overlapping input and output.

 Both mechanisms generate a runtime call that is executed before any
 use of the buffer variable. See Section 16.1.5, "Lazy Evaluation," and
 Section 16.1.6, "Concurrent I/O," for complete details.


 8.3  File Structures


 MS-Pascal files have two basic structures: BINARY and ASCII. These two
 structures correspond to raw data files and human-readable textfiles,
 respectively.


 8.3.1  BINARY Structure Files


 The Pascal data type FILE OF type corresponds to MS-Pascal BINARY
 structure files. These, in turn, correspond to unformatted operating
 system files.

 Under operating systems that divide files into records, every record
 is one component of the file type (not to be confused with the record
 type). Primitive procedures such as GET and PUT operate on a record basis.
 Under operating systems that do not have their own record structure, the
 primitive procedures GET and PUT transfer a fixed number of bytes per call,
 equal to the length of one component. See Section 8.4, "File Access
 Modes," for further discussion of BINARY files.


 8.3.2  ASCII Structure Files


 The Pascal data type TEXT corresponds to MS-Pascal ASCII structure
 files. These, in turn, correspond to textual operating system files (called
 "textfiles" in this manual).

 The Pascal TEXT type is like a FILE OF CHAR, except that groups of
 characters are organized into "lines" and, to a lesser extent, "pages."
 Primitive file procedures, such as GET and PUT, always operate on a
 character basis.

 However, under operating systems that divide files into records, every
 record is a line (not a character). Even in operating systems that do not
 have their own record structure, other languages and utilities have some
 way of organizing bytes into lines of characters.

 MS-Pascal provides a number of special functions and procedures that
 use this line-division feature. Because MS-Pascal does not impose any
 additional formatting on operating system files of most modes (including
 SEQUENTIAL, TERMINAL, and DIRECT), programs in other languages can generate
 and use these files.

 MS-Pascal textfiles (files of type TEXT) are divided into lines with a
 "line marker," conceptually a character not of the type CHAR. In theory, a
 textfile can contain any value of type CHAR. However, under some operating
 systems, writing a particular character (say, CHR (13), carriage return, or
 CHR (10), line feed) may terminate the current line (record). This
 character value is the line marker in this case and, when read, always
 looks like a blank.

 Under other operating systems, there may not be a terminating character.
 Still, as far as you are concerned, every line is followed by a line
 marker that reads as a blank.

 At the extend level, a declaration for a textfile may include an optional
 line length. Setting the line length, which sets record length, is only
 needed for DIRECT mode textfiles. You may specify line length for other
 modes as well, but doing so has no effect.

 Specify the line length of a textfile as a constant in parentheses
 after the word TEXT:

      TYPE NAMEADDR = TEXT (128);
           DEFAULTX = TEXT;
           SMALLBUF = TEXT (2);


 8.4  File Access Modes


 The file modes in MS-Pascal are SEQUENTIAL, TERMINAL, and DIRECT.
 SEQUENTIAL and TERMINAL mode files are available at the standard level;
 all three, including DIRECT mode, are available at the extend level.
 SEQUENTIAL and TERMINAL mode ASCII structure files can have variable length
 records (lines); DIRECT mode files must have fixed length records or lines.

 The declaration of a file in Pascal implies its structure, but not its
 mode. For example, FILE OF STRING (80) indicates BINARY structure; TEXT
 indicates ASCII structure. An assignment like F.MODE := DIRECT sets the
 mode; this only works at the extend level and is currently only needed to
 set DIRECT mode.


 8.4.1  TERMINAL Mode Files


 TERMINAL mode files always correspond to an interactive terminal or
 printer. TERMINAL mode files, like SEQUENTIAL mode files, are opened at the
 beginning of the file for either reading or writing. Records are accessed
 one after the other until the end of the file is reached.

 Operation of TERMINAL mode input for terminals depends on the file
 structure (ASCII or BINARY). For ASCII structure (type TEXT), entire lines
 are read at one time. This permits the usual operating system intraline
 editing, including backspace, advance cursor, and cancel. Characters are
 echoed to the terminal screen while the line is being typed.

 If the target operating system does not support intraline editing or
 echo, the MS-Pascal file system interface provides it. However, since an
 entire line is read at once, you cannot read the characters as you type
 them, invoke several prompts and responses on the same line, and so on.

 For BINARY structure TERMINAL mode (usually type FILE OF CHAR), you
 can read characters as you type them. No intraline editing or echoing is
 done. This method permits screen editing, menu selection, and other
 interactive programming on a keystroke rather than line basis.

 TERMINAL mode files use lazy evaluation to properly handle normal
 interactive reading of the terminal keyboard. See Section 16.1.5, "Lazy
 Evaluation," for details.


 8.4.2  SEQUENTIAL Mode Files


 SEQUENTIAL mode files are generally disk files or sequential access
 devices. Like TERMINAL mode files, SEQUENTIAL mode files are opened at the
 beginning of the file for either reading or writing, and records are
 accessed one after another until the end of the file. Standard Pascal
 files are in SEQUENTIAL mode by default (except for INPUT and OUTPUT).


 8.4.3  DIRECT Mode Files


 DIRECT mode files are generally disk files or other random access
 devices. DIRECT mode files and the ability to specify the access mode for
 file I/O are available options at the extend level of MS-Pascal.

 DIRECT mode ASCII structure files, as well as all BINARY structure
 files, have fixed-length records, where a record is either a line or file
 component. (Here the term "record" refers not to the normal Pascal record
 type, but to a disk structuring unit.) DIRECT files are always opened for
 both reading and writing, and records can be accessed randomly by record
 number. There is no record number zero; records begin with record number
 one.


 8.5  The Predeclared Files: INPUT and OUTPUT


 Two files, INPUT and OUTPUT, are predeclared in every MS-Pascal
 program. These files get special treatment as program parameters and are
 normally required as parameters in the program heading:

      PROGRAM ACTION (INPUT, OUTPUT);

 If there are no program parameters and the program does not use the files
 INPUT and OUTPUT, the heading can look like this:

      PROGRAM ACTION;

 However, you should include INPUT and OUTPUT as program parameters if you
 use them, either explicitly or implicitly, in the program itself:

       WRITE (OUTPUT, 'Prompt: ')  {Explicit use}
       WRITE ('Prompt: ')          {Implicit use}

 These examples would generate a warning if OUTPUT was not declared in the
 program heading. The only effect of INPUT and OUTPUT as program parameters
 is to suppress this warning.

 Although you may redefine the identifiers INPUT and OUTPUT, the file
 assumed by textfile input and output procedures and functions (e.g., READ,
 EOLN) is the predeclared definition. The procedures RESET (INPUT) and
 REWRITE (OUTPUT) are generated automatically, whether or not INPUT and
 OUTPUT are present as program parameters (you may also use these procedures
 explicitly).

 INPUT and OUTPUT have ASCII structure and TERMINAL mode. They are
 initially connected to your terminal and opened automatically. At the
 extend level of MS-Pascal, you can change these characteristics if you
 wish.


 8.6  File I/O: Extend Level


 A file variable in MS-Pascal is really a record, of type FCBFQQ, called
 a file control block. At the extend level, a few standard fields in this
 record help you handle file modes and error trapping.

 Additional fields and the record type FCBFQQ itself can be used at the
 system level, described in Section 8.7, "File I/O: System Level." Along
 with access to certain FCB fields, extend level I/O also includes the
 following procedures:

      ASSIGN      READFN
      CLOSE       READSET
      DISCARD     SEEK

 See Section 16.3, "Extend Level I/O," for a description of these
 procedures.

 Use the normal record field syntax to access FCB fields. For a file
 F, the fields are named F.MODE, F.TRAP, and F.ERRS. You may change or
 examine these fields at any time.

 1.  F.MODE : = FILEMODES

     This field contains the mode of the file: SEQUENTIAL, TERMINAL, or
     DIRECT. These values are constants of the predeclared enumerated type
     FILEMODES. The file system uses the MODE field only during RESET and
     REWRITE. Thus, changing the MODE field of an open file has no effect
     and is, in fact, discouraged. Except for INPUT and OUTPUT, which have
     TERMINAL mode, a file's mode is SEQUENTIAL by default.

     RESET and REWRITE change the mode from SEQUENTIAL to TERMINAL if they
     discover that the device being opened is a terminal or printer and if
     the target operating system allows it. This is useful in programs
     designed to work either interactively or in batch mode. You must set
     DIRECT mode before RESET or REWRITE if you plan to use SEEK on a file.

 2.  F.TRAP := BOOLEAN

     If this field is TRUE, error trapping for file F is turned on. Then,
     if an input/output error occurs, the program does not abort and
     the error code can be examined. Initially, F.TRAP is set FALSE. If
     FALSE and an I/O error occurs, the program aborts.

 3.  F.ERRS := WRD(0)..15

     This field contains the error code for file F. An error code of zero
     means no error; values from 1 to 15  imply an error condition. If you
     attempt a file operation other than CLOSE or DISCARD and F.ERRS is not
     zero, the program immediately aborts if F.TRAP is FALSE. If F.TRAP is
     TRUE and F.ERRS is not zero, the attempted file operation is ignored
     and the program continues. After the error is trapped, the program
     must set F.ERRS back to 0 to prevent succeeding file operations from
     being ignored.

     CLOSE and DISCARD do not examine the initial value of F.ERRS, so they
     are never ignored and do not cause an immediate abort. Nevertheless,
     if CLOSE or DISCARD themselves generate an error condition, F.TRAP is
     used to determine whether to trap the error or to abort.

     An operation ignored because of an error condition does not change the
     file itself, but may change the buffer variable or READ procedure
     input variables.

 Also at the extend level, you may set the line length for a textfile,
 as shown:

      TYPE SMALLBUF = TEXT (16);
      VAR RANDOMTEXT : TEXT (132);

 Declaring line length applies only to DIRECT mode ASCII structure files,
 where the line length is the record length used for reading and writing.
 Setting the line length has no effect on other ASCII files.


 8.7  File I/O: System Level


 At the system level of MS-Pascal, you can call procedures and functions
 that have a formal reference parameter of type FCBFQQ with an actual
 parameter of the type FILE OF type or TEXT, or the identical FCBFQQ type.

 The FCBFQQ type is the underlying record type used to implement the
 file type in MS-Pascal. The interface for the target system FCBFQQ type
 (and any other types needed) is usually part of the internal file system.
 Thus, procedures and functions that reference FCBFQQ parameters can be
 called with any file type, including predeclared procedures and functions
 like CLOSE and READ.

 An FCBFQQ type variable can be passed to procedures like READLN and
 WRITELN that require a textfile. This permits, for example, calling
 directly the interface routines on the target operating system, working
 with mixtures of MS-Pascal and MS-FORTRAN (which share the file system
 interface but have special FCBFQQ fields), and other special file system
 activities.

 Such activities require a sound knowledge of the file system. See
 Section 10.2, "An Overview of the File System," in the Microsoft Pascal
 Compiler User's Guide for a discussion of the file system interface and
 file control block.



 Chapter 9  Reference and Other Types

 

 9.1  Reference Types

       9.1.1  Pointer Types

       9.1.2  Address Types

       9.1.3  Segment Parameters for the Address Types

       9.1.4  Using the Address Types

       9.1.5  Notes on Reference Types

 9.2  PACKED Types

 9.3  Procedural and Functional Types



 The array, record, and set types discussed in Chapter 7, "Arrays, Records,
 and Sets," let you describe data structures whose form and size are
 predetermined and whose components are accessed in a standard way. The file
 type, described in Chapter 8, "Files," is a structure that varies in size
 but whose form and means of access are predetermined.

 In this chapter, you will find a discussion of reference types, which
 allow data structures that vary in size and form and whose means of access
 is particular to the programming problem involved. Also included are notes
 on PACKED types and procedural and functional types.


 9.1  Reference Types


 A reference to a variable or constant is an indirect way to access it. The
 pointer type is an abstract type for creating, using, and destroying
 vairables allocated from an area called the heap. The heap is a dynamically
 growing and shrinking region of memory allocated for pointer variables.

 Microsoft Pascal also provides two machine-oriented address types: one
 for addresses that can be representevd in 16 bits, the other for addresses
 that require 32 bits.

 Pointers are generally used for trees, graphs, and list processing.
 Use of pointers is portable, structured, and relatively safe.

 Address types provide an interface to the hardware and operating
 system; their use is frequently unstructured, machine specific, low level,
 and unsafe. Both pointers and address types are dicussed further in the
 following sections.


 9.1.1  Pointer Types


 A pointer type is a set of values that point to variables of a given type.
 The type of the variables pointed to is called the "reference type.''
 Reference variables are all dynamically allocated from the heap with the
 NEW procedure. Pascal variables are normally allocated on the stack or at
 fixed locations.

 You may perform only the following actions on pointers:

     1.  assign them

     2.  test them for equality and inequality with the two
         operators = and < >

     3.  pass them as value or reference parameters

     4.  dereference them with the up arrow (^)

 Every pointer type includes the pointer value NIL. Pointers are
 frequently used to create list structures of records, as shown in the
 following example:


      TYPE
        TREETIP =^TREE
        TREE = RECORD
                 VAL : INTEGER;
                    {Value of TREE cell.}
                 LEFT, RIGHT : TREETIP
                    {Pointers to other TREETIP cells.}
                    {Note recursive definition.}
               END;

 Unlike most type declarations, the declaration for a pointer type can
 refer to a type of which it is itself a component. The declaration can also
 refer to a type declared later in the same TYPE section, as in TREE and
 TREETIP in the previous example.

 Such a declaration is called a forward pointer declaration and
 permits recursive and mutually recursive structures. Because pointers are
 so often used in list structures, forward pointer declarations occur
 frequently.

 The compiler checks for one ambiguous pointer declaration. Suppose the
 previous example was in a procedure nested in another procedure that also
 declared a type TREE. Then the reference type of TREETIP could be either
 the outer definition or the one following in the same TYPE section. MS-
 Pascal assumes the TREE type intended is the one later in the same TYPE
 section and gives the warning:

      Pointer Type Assumed Forward

 At the extend level, a pointer can have a super array type as a
 referent type. The actual upper bounds of the array are passed to the NEW
 procedure to create a heap variable of the correct size. Forward pointer
 declarations of the super array type are not allowed.

 MS-Pascal conforms to the ISO requirement for strict compatibility
 between pointers. For example, you cannot declare two pointers with
 different types and then assign or compare them, even if they happen to
 point to the same underlying type. For example:

      VAR PRA : ^REAL;
          PRE : ^REAL;
      BEGIN PRA := PRE {This is illegal!}
      END;

 Programs usually contain only one type declaration for a pointer to a
 given type. In the TREETIP example, the type of LEFT and RIGHT could be
 ^TREE instead of TREETIP, but then you couldn't assign variables of type
 TREETIP to these fields. However, it is sometimes useful to make sure that
 two classes of pointers are not used together, even if they point to the
 same type.

 For example, suppose you have a type RESOURCE kept in a list and
 declare two types, OWNER and USER, of type ^RESOURCE. The compiler would
 catch assignment of OWNER values to USER variables and vice versa and issue
 a warning message.

 In theory, pointers have nothing to do with actual machine addresses.
 In fact, a pointer may be implemented in different ways on different target
 machines. A pointer may be implemented as a normal address, as a segment
 offset address, as an offset from one or more fixed locations, or as an
 indirect address, among other possibilities.

 If the initialization checking switch is on, a newly created pointer
 has an uninitialized value. If the NIL checking switch is on, pointer
 values are tested for various invalid values. Invalid values include NIL,
 uninitialized values, reference to a heap item that has been DISPOSEd, or a
 value that is not valid as a heap reference.


 9.1.2  Address Types


 As a system implementation language, MS-Pascal needs a method of creating,
 manipulating, and dereferencing actual machine addresses. The pointer type
 is only applicable to variables in the heap.

 There are two kinds of addresses: relative and segmented. The
 keywords ADR and ADS refer to the relative address type and the segmented
 address type, respectively. As the following example shows, you use the
 keywords both as type clause prefixes and as prefix operators:

      VAR INT_VAR : INTEGER;
          REAL_VAR : REAL;
          A_INT : ADR OF INTEGER;
          {Declaration of ADR variable}
          AS_REAL : ADS OF REAL;
          {Declaration of ADS variable}

      BEGIN
        INT_VAR := 1;
        {Normal integer variable}
        REAL_VAR := 3.1415;
        {Normal real variable}
        A_INT := ADR INT_VAR;
        {ADR used as operator}
        AS_REAL := ADS REAL_VAR;
        {ADS used as operator}
        WRITELN (A_INT^, AS_REAL^)
        {Note use of up arrow to dereference}
        {the address types.}
        {Output is 1 and 3.1415.}
      END.

 The characteristics of relative and segmented address types, as
 implemented for different machines, are shown in Table 9.1.


 Table 9.1.
 Relative and Segmented Machine Addresses
ķ
 Machine           ADR                   ADS
 
 8080              16-bit absolute       Same as ADR

 8086              16-bit default        16-bit offset,
                   data segment offset   16-bit segment

 Z8000             16-bit data           Same as ADR
 (unsegmented)     absolute

 Z8000             Same as ADS           16-bit segment,
 (segmented)                             16-bit offset

 See your Microsoft Pascal Compiler User's Guide for details specific
 to your implementation of the compiler.

 In MS-Pascal, you may declare a variable that is an address:

      VAR  X : ADR OF BYTE;

 Then, with the following record notation, you can assign numeric
 values to the actual variable:

      X.R := 16#FFFF

 In an unsegmented environment, the .R (relative address) is the only
 record field available for ADR and ADS addresses.

 Since MS-Pascal allows nondecimal numbering, you may specify the
 assigned value in hexadecimal notation. You may also assign to a
 segment field with the ADS type in a segmented environment, using the
 field notation .S (segment address). Thus, you may declare a variable of
 an ADS type and then assign values to its two fields:

      VAR Y : ADS OF WORD;
        .
        .
      Y.S := 16#0001
      Y.R := 16#FFFF

 As shown above, any 16-bit value can be directly assigned to address
 type variables, using the .R and .S fields. The ADR and ADS operators
 obtain these addresses directly. The example below assigns addresses this
 way to the variables X and Y:

      VAR  X : ADR OF BYTE;
           Y : ADS OF WORD;
           W : WORD;
           B : BYTE;
             .
             .
           X := ADR B;
           Y := ADS W;

 MS-Pascal supports these two predeclared address types:

      ADRMEM = ADR OF ARRAY [0..32766] OF BYTE;
      ADSMEM = ADS OF ARRAY [0..32766] OF BYTE;

 Since the type referred to by the address is an array of bytes, byte
 indexing is possible. For example, if A is of type ADRMEM, then A^[15] is
 the byte at the address A.R + 15, where .R specifies an actual 16-bit
 address.

 You can use the address types for a constant address (a form of
 structured constant); you may also take the address of a constant or
 expression. For example:

      TYPE ADRWORD = ADR OF WORD;
           ADSWORD = ADS OF WORD;
      VAR W : WORD;
          R : ADRWORD;
      CONST CONADR = ADRWORD (1234);
      BEGIN
        W := CONADR^;
        {Get word at address 1234}
        W := ADSWORD (0, 32)^;
        {Get word at address 0:32}
        W := (ADS W).S;
        {Get value of DS segment register}
        R := ADR '123';
        {Get address of a constant value}
        R := ADR (W DIV 2 + 1)
        {Get address of expression value}
      END;

 However, constants or expressions that yield addresses cannot currently be
 used as the target of an assignment (or as a reference parameter or WITH
 record), as shown:

      CONST ADSCON = ADSWORD (256, 64);   {OK}
      FUNCTION SOME_ADDRESS: ADSWORD;     {OK}
      BEGIN
        ADSWORD (0, 32)^ := W; {Not permitted}
        ADSCON^ := 12; {Not permitted}
        SOME_ADDRESS^ := 100 {Not permitted}
      END;


 9.1.3  Segment Parameters for the Address Types


 Two keywords, VARS and CONSTS, are available as parameter prefixes, like
 VAR and CONST, to pass the segmented address of a variable. If P is of
 type ADS FOO, then P^ can be passed to a VARS formal parameter, such as
 VARS X : FOO, but cannot be passed to a VAR formal parameter.

 In a segmented machine environment, a default data segment is assumed,
 in which case a VAR parameter is passed as the default data segment offset
 of a variable. A VARS parameter is passed as both the segment value and the
 offset value.

 In the 8086 environment, both VARS parameters and ADS variables have
 the offset (.R) value in the WORD with the lower address and the segment
 (.S) value in the address plus two.

 In the segmented Z8000 environment, the segment (.S) value is in the
 lower address and the offset (.R) value in the address plus two. Also, the
 ADR type is identical to the ADS type.

 In the nonsegmented environment (e.g., 8080), VAR and CONST are
 identical to VARS and CONSTS. Since ADS and ADR are identical in a
 nonsegmented environment, the ADS type is useful in situations where the
 target environment may change. For example, in MS-Pascal, some primitive
 file system calls are declared with ADS parameters.

 In pointer type declarations, the up arrow (^) prefixes the type
 pointed to; in program statements, it dereferences a pointer so that the
 value pointed to can be assigned or operated on. The up arrow also
 dereferences ADR and ADS types in program statements.

 Component selection with the up arrow (^) is performed before the
 unary operators ADR or ADS. Because the up arrow (^) selector can appear
 after any address variable to produce a new variable, it can occur, for
 example, in the target of an assignment, a reference parameter, as well as
 in expressions. Since ADS and ADR are prefix operators, they are used only
 in expressions, where they apply only to a variable or constant or
 expression.

 Pascal is a strongly typed language; two pointer variables are
 compatible only if they have the same type (it is not enough that they
 point to the same type). However, two address types are considered the
 same type if they are both ADR or both ADS types. This lets you assign an
 ADR OF WORD to an ADR OF STRING (200). Such an assignment would make it
 easy to wipe out part of memory by assigning a variable of type
 STRING (200) to the 200 bytes starting at the address of a WORD variable.

 If P1 is type ADR OF STRING (200) and P2 is any ADR OF type, the
 assignment P1^ := P2^ generates fast code with no range checking. Although
 this capability is not safe, operating systems and other software sometimes
 require it.

 ADR and ADS are not compatible with each other, but the .R notation
 should overcome or reduce the problem.


 9.1.4  Using the Address Types


 Within limits, you may combine and intermingle the two address types.
 The following example illustrates the rules that apply in a segmented
 environment:

      VAR
        P : ADS OF DATA;
        {P is segmented address of type DATA.}
        Q : ADR OF DATA;
        {Q is relative address of type DATA.}
        X : DATA;
        {X is some variable of type DATA.}

      BEGIN
        P := ADS X;
        {Assign the address of X to P.}
        X := P^;
        {Assign to X the value pointed to by P.}
        P := ADS P^;
        {Assign to P the address of the value whose}
        {address is pointed to by P. P is unchanged}
        {by this assignment.}
        Q := ADR X;
        {Assign the relative address of X to Q.}
        Q.R  := (ADR X).R;
        {Assign the relative address of X to Q,}
        {using the WORD type.}
        P := ADS Q^;
        {Assign the address of the variable at Q to P.}
        {You can always apply ADS to ADR^.}
        Q := ADR P^;
        {Illegal; you cannot apply ADR to ADS^.}
        P.R := 16#8000;
        {Assign 32768 to P's offset field.}
        P.S := 16;
        {Assign 16 to P's segment field.}
        Q.R := P.R + 4
        {Assign P's offset plus 4 to be the value of Q.}
      END;

 See also the examples given in Section 9.1.2, "Address Types."


 9.1.5  Notes on Reference Types


 The address type and pointer type should be treated as two distinct types.
 The pointer type, in theory, is just an undefined mapping from one variable
 to another variable. The method of implementation is undefined. However,
 the address type deals with actual machine addresses.

 Therefore, the pointer type is an abstract data type that works the
 same in all implementations; the address type is generally not portable,
 unless used with some caution. Address types are portable only if you
 restrict yourself to using ADS and never assign to fields. Even with these
 restrictions, however, they can be quite useful.

 The following special facilities that use pointer variables are not
 allowed with address variables.

     1.  The NEW and DISPOSE procedures are only permitted with pointers.
         NIL does not apply to the address type. There are no special
         address values for empty, uninitialized, or invalid addresses.

     2.  The type "address of super array type" is not supported in the same
         way as "pointer to super array type." Getting the address of a
         super array variable is still permitted with ADR and ADS. For
         example, if a procedure or function formal parameter is declared as
         VAR S : STRING, then within the procedure or function, the
         expression ADS S is fine. Unlike a pointer, the address does not
         contain any upper bounds.


 9.2  PACKED Types


 Any of the structured types can be PACKED. This could economize storage
 at the possible expense of access time or access code space. However,
 in MS-Pascal, some limitations on the use of PACKED structures currently
 apply:

     1.  The prefix PACKED is always ignored, except for type checking, in
         sets, files, and arrays of characters. In most versions of MS-
         Pascal it has no actual effect on the representation of records and
        other arrays. Furthermore, PACKED can only precede one of the
         structure names ARRAY, RECORD, SET, or FILE; it cannot precede a
         type identifier. For example, if COLORMAP is the identifier for an
         unpacked array type, "PACKED COLORMAP" is not accepted.

     2.  A component of a PACKED structure cannot be passed as a reference
         parameter or used as the record of a WITH statement, unless the
         structure is of a string type. Also, obtaining the address of a
         PACKED component with ADR or ADS is not permitted.

     3.  A PACKED prefix only applies to the structure being defined:  any
         components of that structure that are also structures are not
         packed unless you explicitly include the reserved word PACKED in
         their definition. The only exception to this rule, n-dimensional
         arrays, is discussed in Section 7.1, "Arrays."


 9.3  Procedural and Functional Types


 Procedural and functional types are different from other MS-Pascal
 types. (Wherever the term "procedural" is used from here on, both
 procedural and functional is implied.) You may not declare an identifier
 for a procedural type in a TYPE section; nor may you declare a variable of
 a procedural type. However, you may use procedural types to declare the
 type of a procedural parameter, and in this sense they conform to the
 Pascal idea of a type.

 A procedural type defines a procedure or function heading and gives
 any parameters. For a function, it also defines the result type. The
 syntax of a procedural type is the same as a procedure or function heading,
 including any attributes. There are no procedural variables in MS-Pascal,
 only procedural parameters.

 Example of a procedural type declaration:

      PROCEDURE ZERO (FUNCTION FUN (X, Y : REAL) : REAL)

 The parameter identifiers in a procedural type (X and Y in the
 previous example) are ignored; only their type is important.

 See Section 14.4.3, "Procedural and Functional Parameters," for more
 information about procedural types in MS-Pascal.



 Chapter 10  Constants

 

 10.1  What Is a Constant?

 10.2  Declaring Constant Identifiers

 10.3  Numeric Constants

        10.3.1  REAL Constants

        10.3.2  INTEGER, WORD, and INTEGER4 Constants

        10.3.3  Nondecimal Numbering

 10.4  Character Strings

 10.5  Structured Constants

 10.6  Constant Expressions



 10.1  What Is a Constant?


 A constant is a value that is known before a program starts and that will
 not change as the program progresses. Examples of constants include the
 number of days in the week, your birthdate, the name of your dog, or the
 phases of the moon.

 A constant may be given an identifier, but you cannot alter the value
 associated with that identifier during the execution of the program. When
 you declare a constant, its identifier becomes a synonym for the constant
 itself.

 Each constant implicitly belongs to some category of data:

     1.  Numeric constants (discussed in Section 10.3, "Numeric Constants")
         are one of the several number types: REAL, INTEGER, WORD, or
         INTEGER4.

     2.  Character constants (discussed in Section 10.4, "Character
         Strings") are strings of characters enclosed in single quotation
         marks and are called "string literals" in Microsoft Pascal.

     3.  Available at the extend level, structured constants (discussed in
         Section 10.5, "Structured Constants") include constant arrays,
         records, and typed sets.

 Also available at the extend level, constant expressions (discussed in
 Section 10.6, "Constant Expressions") let you compute a constant based on
 the values of previously declared constants in expressions.

 The identifiers defined in an enumerated type are constants of that
 type and cannot be used directly with numeric (or string) constant
 expressions. These identifiers can be used with the ORD, WRD, or CHR
 functions (e.g., ORD (BLUE)). The extend level also permits directly
 reading and writing the enumerated type's constant identifiers as
 character strings.

 TRUE and FALSE are predeclared constants of type BOOLEAN and can be
 redeclared. NIL is a constant of any pointer type; however, because it is
 a reserved word, you may not redefine it. Also, the null set is a constant
 of any set type.

 Numeric statement labels have nothing to do with numeric constants;
 you may not use a constant identifier or expression as a label.
 Internally,  all constants are limited in length to a maximum of 255
 bytes.


 10.2  Declaring Constant Identifiers


 Declaring a constant identifier introduces the identifier as a synonym
 for the constant. You put these declarations in the CONST section of a
 compiland, procedure, or function.

 The general form of a constant identifier declaration is the identifier
 followed by an equal sign and the constant value. The following program
 fragment includes three statements that identify constants (beginning
 after the word "CONST"):

      PROGRAM DEMO (INPUT, OUTPUT);
      CONST DAYS_IN_YEAR = 365;
            DAYS_IN_WEEK = 7;
            NAME_OF_PLANET = 'EARTH';

 In this example, the numbers 365 and 7 are numeric constants; must be
 enclosed in single quotation marks.

 When you compile a program, the constant identifiers are not actually
 defined until after the declarations are processed. Thus, a constant
 declaration like the following has no meaning:

      N = -N

 The ISO standard defines a strict order in which to set out the
 declarations in the declaration section of a program:

      CONST MAX = 10;
      TYPE NAME = PACKED ARRAY [1..MAX] OF CHAR;
      VAR FIRST : NAME;

 MS-Pascal relaxes this order and, in fact, allows more than one instance of
 each kind of declaration:

      TYPE COMPLEX = RECORD R, I : REAL END;
      CONST PII = COMPLEX (3.1416, 00);
      VAR PIX : COMPLEX;
      TYPE IVEC = ARRAY [1..3] OF COMPLEX;
      CONST PIVEC = IVEC (PII, PII, COMPLEX (0.0, 1.0));


 10.3  Numeric Constants


 Numeric constants are irreducible numbers such as 45, 12.3, and 9E12.
 The notation of a numeric constant generally indicates its type: REAL,
 INTEGER, WORD, or INTEGER4.

 Numbers can have a leading plus sign (+) or minus sign (-), except
 when the numbers are within expressions. Therefore:

      ALPHA := +10       {Is legal}
      ALPHA + -10        {Is illegal}

 Blanks embedded within constants are not permitted.

 The compiler truncates any number that exceeds a certain maximum
 number of characters and gives a warning when this occurs. The maximum
 length of constants (either 19 or 31) is the same as the maximum length of
 identifiers. For the maximum length of constants and identifiers in a
 particular version of the language, see Appendix B "Version Specifics," in
 your Microsoft Pascal Compiler User's Guide.

 The syntax for numeric constants applies not only to the actual text
 of programs, but also to the content of textfiles read by a program.

 Examples of numeric constants:

       123                0.17
      +12.345             007
      -1.7E-10           -26.0
       17E+3              26.0E12
      -17E3               1E1

 Numeric constants can appear in any of the following:

     1.  CONST sections

     2.  expressions

     3.  type clauses

     4.  set constants

     5.  structured constants

     6.  CASE statement CASE constants

     7.  variant record tag values

 The different types of numeric constants are discussed in detail in the
 following sections.


 10.3.1  REAL Constants


 The type of a number is REAL if the number includes a decimal point or
 exponent. The REAL value range depends on the REAL number unit of the
 target machine. Generally, either the IEEE or the Microsoft REAL number
 format is used. This provides about seven digits of precision, with a
 maximum value of about 1.701411E38.

 There is, however, a distinction between REAL values and REAL constants.
 The REAL constant range may be a subset of the REAL value range. In
 Microsoft format, REAL numeric constants must be greater than or equal
 to 1.0E-38 and less than 1.0E+38. In IEEE format, REAL numeric constants
 are kept in double precision and so can range from about 1E-306 to 1E+306.

 The compiler issues a warning if there is not at least one digit on
 each side of a decimal point. A REAL number starting or ending with a
 decimal point may be misleading. For example, because left parenthesis-
 period substitutes for left square bracket, and right parenthesis-period
 for right square bracket, the following:

      (.1 + 2.)

 is interpreted as:

      [1 + 2]

 Scientific notation in REAL numbers (as in 1.23E-6 or 4E7) is supported.
 The decimal point and exponent sign are optional when an exponent is given.
 Both the uppercase "E" and the lowercase "e" are allowed in REAL numbers.
 "D" and "d" are also allowed to indicate an exponent. This provides
 compatibility with other languages.

 When IEEE REAL4 and REAL8 format are used, all real constants are
 stored in REAL8 (double precision) format. If you require a single
 precision REAL4 constant, declare a REAL4 variable and give it your real
 constant value in a VALUE section. (You may wish to give this variable the
 READONLY attribute as well.)

 Versions of the compiler that run on one machine but generate code for
 another may lose a small amount of significance in REAL constants.


 10.3.2  INTEGER, WORD, and INTEGER4 Constants


 The type of a non-REAL numeric constant is INTEGER, WORD, or INTEGER4.
 Table 10.1 shows the range of values that constants of each of these types
 can assume.


 Table 10.1.
 INTEGER, WORD, and INTEGER4 Constants
ķ
 Type         Range of Values         Predeclared
              (minimum/maximum)       Constant
 
 INTEGER      -MAXINT to MAXINT       MAXINT=32767

 WORD          0 to MAXWORD           MAXWORD=65535

 INTEGER4     -MAXINT4 to MAXINT4     MAXINT4=2147483647

 MAXINT, MAXWORD, and MAXINT4 are all predeclared constant identifiers.

 One of three things happens when you declare a numeric constant
 identifier:

     1.  A constant identifier from -MAXINT to MAXINT becomes an INTEGER.

     2.  A constant identifier from MAXINT+1 to MAXWORD becomes a WORD.

     3.  A constant identifier from -MAXINT4 to -MAXINT-1 or MAXWORD+1 to
         MAXINT4 becomes an INTEGER4.

 However, any INTEGER type constant (including constant expressions and
 values from -32767 to -1) automatically changes to type WORD; if the
 INTEGER value is negative, 65536 is added to it and the underlying 16-bit
 value is not changed.

 For example, you can declare a subrange of type WORD as WRD(0)..127;
 the upper bound of 127 is automatically given the type WORD. The reverse
 is not true; constants of type WORD are not automatically changed to type
 INTEGER.

 The ORD and WRD functions also change the type of an ordinal constant
 to INTEGER or WORD. Also, any INTEGER or WORD constant automatically
 changes to type INTEGER4 if necessary, but the reverse is not true.

 Examples of relevant conversions are given in Table 10.2.


 Table 10.2
 Constant Conversions
ķ
 Constant          Assumed Type
 
         0         INTEGER could become WORD or INTEGER4

    -32768         INTEGER4 only

     32768         WORD could become INTEGER4

  0..20000         INTEGER subrange

 Constant          Assumed Type

  0..50000         WORD subrange

  0..80000         Invalid: no INTEGER4 subranges

 -1..50000         Invalid: becomes 65535..50000
                   (i.e., -1 is treated as 65536)

 At the standard level, any numeric constant (i.e., literal or identifier)
 may have a plus (+) or minus (-) sign.


 10.3.3  Nondecimal Numbering


 At the extend level, MS-Pascal supports not only decimal number notation,
 but also numbers in hexadecimal, octal, binary, or other base numbering
 (where the base can range from 2 to 36). The number sign (#) acts as a
 radix separator.

 Examples of numbers in nondecimal notation:

      16#FF02
      10#987
       8#776
       2#111100

 Leading zeros are recognized in the radix, so a number like 008#147 is
 permitted. In hexadecimal notation, upper or lowercase letters A through F
 are permitted. A nondecimal constant without the radix (such as #44) is
 assumed to be hexadecimal. Nondecimal notation does not imply a WORD
 constant and may be used for INTEGER, WORD, or INTEGER4 constants. You
 must not use nondecimal notation for REAL constants or numeric statement
 labels.


 10.4  Character Strings


 Most Pascal manuals refer to sequences of characters enclosed in single
 quotation marks as "strings." In MS-Pascal, they are called "string
 literals" to distinguish them from string constants, which may be
 expressions, or values of the STRING type.

 A string constant contains from 1 to 255 characters. A string
 constant longer than one character is of type PACKED ARRAY [1..n] OF
 CHAR, also known in MS-Pascal as the type STRING (n). A string constant
 that contains just one character is of type CHAR. However, the type
 changes from CHAR to PACKED ARRAY [1..1] OF CHAR (e.g., STRING (1)) if
 necessary. For example, a constant ('A') of type CHAR could be assigned to
 a variable of type STRING (1).

 A literal apostrophe (single quotation mark) is represented by two
 adjacent single quotation marks (e.g., 'DON''T GO'). The null string ('')
 is not permitted. A string literal must fit on a line. The compiler
 recognizes string literals enclosed in double quotations marks (" ") or
 accent marks (), instead of single quotation marks, but issues a warning
 message when it encounters them.

 The constant expression feature (discussed in Section 10.6, "Constant
 Expressions") permits string constants made up of concatenations of
 other string constants, including string constant identifiers, the CHR ()
 function, and structured constants of type STRING. This is useful for
 representing string constants that are longer than a line or that contain
 nonprinting characters. For example:

    'THIS IS UNDERLINED' * CHR(13) * STRING (DO 18 OF '_')

 The LSTRING feature of MS-Pascal adds the super array type LSTRING.
 LSTRING is similar to PACKED ARRAY [0..n] OF CHAR, except that element 0
 contains the length of the string, which can vary from 0 to a maximum of
 255. (See Section 7.2.2, "LSTRINGs," for a discussion of LSTRINGs.) For
 now, note that, if necessary, a constant of type STRING (n) or CHAR changes
 automatically to type LSTRING.

 NULL is a predeclared constant for the null LSTRING, with the element
 0 (the only element) equal to CHR (0). NULL cannot be concatenated, since
 it is not of type STRING. It is the only constant of type LSTRING.

 Examples of string literal declarations:

      NAME = 'John Jacob';    {a legal string literal}
      LETTER = 'Z';           {LETTER is of type CHAR}
      QUOTED_QUOTE = '''';    {Quotes quote}
      NULL_STRING = NULL;     {legal}
      NULL_STRING = '';       {illegal}
      DOUBLE = "OK";          {generates a warning}


 10.5  Structured Constants


 Standard Pascal permits only the numeric and string constants already
 mentioned, the pointer constant value NIL, and untyped constant sets.

 At the extend level of MS-Pascal, however, you may use constant
 arrays, records, and typed sets. Structured constants can be used
 anywhere a structured value is allowed, in expressions as well as
 in CONST and VALUE sections.

  1.  An array constant consists of a type identifier followed by a
      list of constant values in parentheses separated by commas.

      Example of an array constant:

         TYPE VECT_TYPE = ARRAY [-2..2] OF INTEGER;
         CONST VECT = VECT_TYPE (5, 4, 3, 2, 1);
         VAR A : VECT_TYPE;
         VALUE A := VECT;

  2.  A record constant consists of a type identifier followed by a list of
      constant values in parentheses separated by commas.

      Example of a record constant:

         TYPE REC_TYPE = RECORD
                A, B : BYTE;
                C, D : CHAR
              END;
         CONST RECR = REC_TYPE ( 20, 0, 'A', CHR (20));
         VAR FOO : REC_TYPE;
         VALUE FOO := RECR;

  3.  A set constant consists of an optional set type identifier followed by
      set constant elements in square brackets. Set constant elements are
      separated by commas. A set constant element is either an ordinal
      constant, or two ordinal constants separated by two dots to indicate a
      range of constant values.

      Example of a set constant:

         TYPE COLOR_TYPE = SET OF
            (RED, BLUE, WHITE, GREY, GOLD);
         CONST SETC = COLOR_TYPE [RED, WHITE .. GOLD];
         VAR RAINBOW : COLOR_TYPE;
         VALUE RAINBOW := SETC;

 A constant within a structured array or record constant must have a type
 that can be assigned to the corresponding component type. For records with
 variants, the value of a constant element corresponding to a tag field
 selects a variant, even if the tag field is empty. The number of constant
 elements must equal the number of components in the structure, except for
 super array type structured constants. Nested structured constants are
 permitted.

 An array or record constant nested within another structured constant
 must still have the preceding type identifier. For this reason, a
 super array constant can have only one dimension (see Section 7.2, "Super
 Arrays," for a discussion of super arrays). The size of the representation
 of a structured constant must be from 1 to 255 bytes. If this 255-byte
 limit is a problem, declare a structured variable with the READONLY
 attribute, and initialize its components in a VALUE section.

 Example of a complex structured constant:

      TYPE R3 = ARRAY [1..3] OF REAL;
      TYPE SAMPLE = RECORD I : INTEGER;
                           A : R3;
                           CASE BOOLEAN OF
                           TRUE : (S : SET OF 'A'..'Z';
                                   P : ^SAMPLE);
                           FALSE : (X : INTEGER)
                       END;
      CONST SAMP_CONST = SAMPLE (27, R3 (1.4, 1.4, 1.4),
                        TRUE, ['A','E','I'], NIL);

 Constant elements can be repeated with the phrase DO n OF constant, so
 the previous example could have included "DO 3 OF 1.4" instead of "1.4,
 1.4, 1.4".

 MS-Pascal does not support set constant expressions, such as
 ['_'] + LETTERS, or file constant expressions. The  constant 'ABC' of type
 STRING (3) is equivalent to the structured constant STRING ('A', 'B', 'C').
 LSTRING structured constants are not permitted; use the corresponding
 STRING constants instead.

 Structured constants (and other structured values, such as variables
 and values returned from functions) can be passed by reference using CONST
 parameters. For more information, see Section 14.4, "Procedure and Function
 Parameters."

 There are two kinds of set constants: one with an explicit type, as in
 CHARSET ['A'..'Z'], and one with an unknown type, as in [20..40]. You may
 use either in an expression or to define the value of a constant
 identifier. Set constants with an explicit type may also be passed as a
 reference (CONST) parameter. Sets of unknown type are unpacked, but the
 type changes to PACKED if necessary. Passing sets by reference is
 generally more efficient than passing them as value parameters.


 10.6  Constant Expressions


 Constant expressions in MS-Pascal allow you to compute constants based
 on the values of previously declared constants in expressions. Constant
 expressions can also occur within program statements.

 Example of a constant expression declaration:

      CONST HEIGHT_OF_LADDER = 6;
            HEIGHT_OF_MAN = 6;
            REACH = HEIGHT_OF_LADDER + HEIGHT_OF_MAN;

 Because a constant expression may contain only constants that you have
 declared earlier, the following is illegal:

      CONST MAX = A + B;
            A = 10;
            B = 20;

 Certain functions may be used within constant expressions. For
 example:

      CONST A = LOBYTE (-23) DIV 23;
            B = HIBYTE (-A);

 Table 10.3 shows the functions and operators you may use with REAL,
 INTEGER, WORD, and other ordinal constants, such as enumerated and
 subrange constants.


 Table 10.3.
 Constant Operators and Functions
ķ
 Type of Operand                Functions and Operators
 
 REAL, INTEGER                  Unary plus  (+)
                                Unary minus (-)

 INTEGER, WORD                  +   DIV  OR    HIBYTE()
 Type of Operand                Functions and Operators
INTEGER, WORD                  +   DIV  OR    HIBYTE()
                                -   MOD  NOT   LOBYTE()
                                *   AND  XOR   BYWORD()

 Ordinal types                  <   <=   CHR()   LOWER()
                                >   >=   ORD()   UPPER()
                                =   <>   WRD()

 Boolean                        AND     NOT     OR

 ARRAY                          LOWER()     UPPER()

 Any type                       SIZEOF()    RETYPE()

 Examples of constant expressions:

      CONST FOO = (100 + ORD('X')) * 8#100 + ORD('Y');
            MAXSIZE = 80;
            X = (MAXSIZE > 80) OR (IN_TYPE = PAPERTAPE);
            {X is a BOOLEAN constant}

 In addition to the operators shown in Table 10.3 for numeric
 constants, you may use the string concatenation operator (*) with string
 constants, as follows:

      CONST A = 'abcdef';
            M = CHR (109); {CHR is allowed}
            A_TO_M = A * 'ghijkl' * M;
            {A_TO_M = 'abcdefghijklm'}

 These constants can span more than one line, but are still limited to the
 255 character maximum. These string constant expressions are allowed
 wherever a string literal is allowed, except in metacommands.


 Chapter 11  Variables and Values

 

 11.1  What Is a Variable?

 11.2  Declaring a Variable

 11.3  The VALUE Section

 11.4  Using Variables and Values

        11.4.1  Components of Entire Variables and Values

                 11.4.1.1  Indexed Variables and Values

                 11.4.1.2  Field Variables and Values

                 11.4.1.3  File Buffers and Fields

        11.4.2  Reference Variables

 11.5  Attributes

        11.5.1  The STATIC Attribute

        11.5.2  The PUBLIC and EXTERN Attributes

        11.5.3  The ORIGIN and PORT Attributes

        11.5.4  The READONLY Attribute

        11.5.5  Combining Attributes



 This chapter describes Microsoft Pascal variable types and the ways
 you can set their values and attributes.


 11.1  What Is a Variable?


 A variable is a value that is expected to change during the course of a
 program. Every variable must be of a specific data type. A variable may
 have an identifier.

 If A is a variable of type INTEGER, then the use of A in a program
 actually refers to the data denoted by A. For example:

      VAR A : INTEGER;
           BEGIN
              A := 1;
              A := A + 1
           END;

 These statements would first assign a value of 1 to the data denoted by A,
 and subsequently assign it a value of 2.

 Variables are manipulated by using some sort of notation to denote the
 variable, in the simplest case, a variable identifier. In other cases,
 variables may be denoted by array indices or record fields or the
 dereferencing of pointer or address variables.

 The compiler itself may sometimes create "hidden" variables, allocated
 on the stack, in circumstances like the following:

     1.  When you call a function that will return a structured result, the
         compiler allocates a variable in the caller for the result.

     2.  When you need the address of an expression (e.g., to pass it as a
         reference parameter or to use it as a WITH statement record or with
         ADR or ADS), the compiler allocates a variable for the value of the
         expression.

     3.  The initial and final values of a FOR loop may require allocating a
         variable.

     4.  When the compiler evaluates an expression, it may allocate a
         variable to store intermediate results.

     5.  Every WITH statement requires a variable to be allocated for the
         address of the WITH's record.


 11.2  Declaring a Variable


 A variable declaration consists of the identifier for the new variable,
 followed by a colon and a type.  You may declare variables of the same type
 by giving a list of the variable identifiers, followed by their common
 type.  For example:

      VAR X_COORD, Y_COORD : REAL

 You may declare a variable in any of the following locations:


     1.  the VAR section of a program, procedure, function, module,
         interface, or implementation

     2.  the formal parameter list of a procedure, function, or procedural
         parameter

 In a VAR section, you may declare a variable to be of any legal
 type; in a formal parameter list, you may include only a type identifier
 (i.e., you may not declare a type in the heading of a procedure or
 function).  For example:

      PROCEDURE NAME (GEORGE : ARRAY [1..10] OF COLOR)
      {Illegal; GEORGE is of a new type.}

      VAR VECTOR_A :  VECTOR (10)
      {Legal; VECTOR (10) is a type derived from}
      {a super type.}

 Each declaration of a file variable F of type FILE OF T implies the
 declaration of a buffer variable of type T, denoted by F^. At the
 extend level, a file declaration also implies the declaration of a record
 variable of type FCBFQQ, whose fields are denoted as F.TRAP, F.ERRS,
 F.MODE, and so on. See Section 8.2, "The Buffer Variable," and Section
 8.6, "File I/O:  Extend Level," for further information on buffer variables
 and FCBFQQ fields, respectively.


 11.3  The VALUE Section


 The VALUE section in Microsoft Pascal lets you give initial values to
 variables in a program, module, procedure, or function. You may also
 initialize the variable in an implementation, but not in an interface.

 The VALUE section may include only statically allocated variables,
 that is, any variable declared at the program, module, or implementation
 level, or a variable with the STATIC or PUBLIC attribute. Variables with
 the EXTERN or ORIGIN attribute cannot occur in a VALUE section, since they
 are not allocated by the compiler.

 The VALUE section may contain assignments of constants to entire
 variables or to components of variables. For example:

      VAR ALPHA : REAL;
          ID : STRING (7);
          I : INTEGER;

      VALUE ALPHA := 2.23;
         ID[1] := 'J';
         I := 1;

 However, within a VALUE section, you may not assign a variable to another
 variable. The last line in the following example is illegal, since "I" must
 be a constant:

      CONST MAX = 10;
      VAR I, J : INTEGER;
      VALUE I := MAX;
            J := I;

 If the $rom metacommand is off, variables are initialized by loading the
 static data segment. If the $rom metacommand is on, the VALUE section
 generates an error message since ROM-based systems usually cannot
 statically initialize data.


 11.4  Using Variables and Values


 At the standard level of MS-Pascal, denotation of a variable may designate
 one of three things:

     1.  an entire variable

     2.  a component of a variable

     3.  a variable referenced by a pointer

 A value may be any of the following:

     1.  a variable

     2.  a constant

     3.  a function designator

     4.  a component of a value

     5.  a variable referenced by a reference value

 At the extend level, a function can also return an array, record, or
 set. The same syntax used for variables may be used to denote
 components of the structures these functions return.

 This feature also allows you to dereference a reference type that is
 returned by a function. However, you may only use the function designator
 as a value, not as a variable. For example, the following is illegal:

      F (X, Y)^ := 42;

 Also at the extend level, you may declare constants of a structured type.
 Components of a structured constant use the same syntax as variables of the
 same type. See Section 10.6, "Constant Expressions," for further discussion
 of this topic.

 Examples of structured constant components:

      TYPE REAL3 = ARRAY [1..3] OF REAL;
      {an array type}
      CONST PIES = REAL3 (3.14, 6.28, 9.42);
      {an array constant}
        .
        .
        X := PIES [1] * PIES [3];
        {i.e., 3.14 * 9.42}
        Y := REAL3 (1.1, 2.2, 3.3) [2];
        {i.e., 2.2}


 11.4.1  Components of Entire Variables and Values


 At the standard level, a variable identifier denotes an entire
 variable. A variable, function designator, or constant denotes an entire
 value.

 A component of a variable or value is denoted by the identifier
 followed by a selector that specifies the component. The form of a selector
 depends on the type of structure (array, record, file, or reference).


 11.4.1.1  Indexed Variables and Values

 A component of an array is denoted by the array variable or value,
 followed by an index expression. The index expression must be assignment
 compatible with the index type in the array type declaration. An index
 type must always be an ordinal type. The index itself must be enclosed in
 brackets following the array identifier.

 Examples of indexed variables and values:

      ARRAY_OF_CHAR ['C']
      {Denotes the Cth element.}

      'STRING CONSTANT' [6]
      {Denotes the 6th element, the letter 'G'.}

      BETAMAX [12] [-3]
      BETAMAX [12,-3]
      {These two say the same thing.}

      ARRAY_FUNCTION (A, B) [C, D]
      {Denotes a component of a two-dimensional array}
      {returned by ARRAY_FUNCTION (A, B). A and B are}
      {actual parameters.}

 You may specify the current length of an LSTRING variable, LSTR, in either
 of two ways:

     1.  with the notation LSTR [0], to access the length as a CHAR
         component

     2.  with the notation LSTR.LEN, to access the length as a BYTE value


 11.4.1.2  Field Variables and Values

 A component of a record is denoted by the record variable or value
 followed by the field identifier for the component. Fields are separated by
 the period (.). In a WITH statement, you give the record variable or value
 only once. Within the WITH statement, you may use the field identifier of a
 record variable directly.

 Examples of field variables and values:

      PERSON.NAME := 'PETE'

      PEOPLE.DRIVERS.NAME := 'JOAN'

      WITH PEOPLE.DRIVERS DO NAME := 'GERI'

      RECURSING_FUNC ('XYZ').BETA
      {Selects BETA field of record returned}
      {by the function named RECURSIVE_FUNC.}

      COMPLEX_TYPE (1.2, 3.14).REAL_PART

 Record field notation also applies to files for FCBFQQ fields, to address
 type values for numeric representations, and to LSTRINGs for the current
 length.


 11.4.1.3  File Buffers and Fields

 At any time, only one component of a file is accessible. The accessible
 component is determined by the current file position and represented by the
 buffer variable. Depending on the status of the buffer variable, the
 fetching process may first read the value from the file. (This is called
 "lazy evaluation"; see Section 16.1.5, "Lazy Evaluation," for details.)

 If a file buffer variable is passed as a reference parameter or used
 as a record of a WITH statement, the compiler issues a warning to alert you
 to the fact that the value of the buffer variable may not be correct after
 the position of the file is changed with a GET or PUT procedure.

 Examples of file reference variables:

      INPUT^
      ACCOUNTS_PAYABLE.FILE^


 11.4.2  Reference Variables


 Reference variables or values denote data that refers to some data
 type.  There are three kinds of reference variables and values:

     1.  pointer variables and values

     2.  ADR variables and values

     3.  ADS variables and values

 In general, a reference variable or value "points" to a data object.
 Thus, the value of a reference variable or value is a reference to that
 data object. To obtain the actual data object pointed to, you must
 "dereference" the reference variable by appending an up arrow (^) to the
 variable or value.

 Example using pointer values:

      VAR P, Q : ^INTEGER;
      {P and Q are pointers to integers.}

      NEW (P); NEW (Q);
      {P and Q are assigned reference values to}
      {regions in memory corresponding to data}
      {objects of type INTEGER.}

      P := Q;
      {P and Q now point to the same region}
      {in memory.}

      P^:= 123;
      {Assigns the value 123 to the INTEGER value}
      {pointed to by P.  Since Q points to this}
      {location as well, Q^ is also assigned 123.}

 Using NIL^ is an error (since a NIL pointer does not reference anything).
 At the extend level, you may also append an up arrow (^) to a
 function designator for a function that returns a pointer or address type.
 In this case, the up arrow denotes the value referenced by the return
 value. This variable cannot be assigned to or passed as a reference
 parameter.

 Examples of functions returning reference values:


      DATA1 := FUNK1 (I, J)^
      {FUNK1 returns a reference value. The up arrow}
      {dereferences the reference value returned,}
      {assigning the referenced data to DATA1.}

      DATA2 := FUNK2 (K, L)^.FOO [2]
      {FUNK2 returns a reference value. The up arrow}
      {dereferences the reference value returned. In}
      {this case, the dereferenced value is a record.}
      {The array component FOO [2] of that record is}
      {assigned to the variable DATA2.}

 If P is of type ADR OF some type, then P.R denotes the address value of
 type WORD.  If P is of type ADS OF some type, then P.R denotes the offset
 portion of the address and P.S denotes the segment portion of the address.
 Both portions are of type WORD.

 Examples of address variables:

      BUFF_ADR.R
      DATA_AREA.S


 11.5  Attributes


 At the extend level of MS-Pascal, a variable declaration or the heading
 of a procedure or function may include one or more attributes. A variable
 attribute gives special information about the variable to the compiler.

 Table 11.1 displays the attributes provided by MS-Pascal for
 variables.


 Table 11.1
 Attributes for Variables
ķ
 Attribute         Variable
 
 STATIC            Allocated at a fixed location, not on the stack

 PUBLIC            Accessible by other modules with EXTERN, implies STATIC

 EXTERN            Declared PUBLIC in another module, implies STATIC

 ORIGIN            Located at specified address, implies STATIC

 PORT              I/O address, implies STATIC

 Attribute         Variable

 READONLY          Cannot be altered or written to

 The EXTERN attribute is also a procedure and function directive; PUBLIC and
 ORIGIN are also procedure and function attributes. See Section 14.3,
 "Attributes and Directives," for a discussion of procedure and function
 attributes and directives. The following sections, 11.5.1 through 11.5.5,
 discuss each of the variable attributes in detail.

 You may only give attributes for variables in a VAR section. Specifying
 variable attributes in a TYPE section or a procedure or function parameter
 list is not permitted.

 You give one or more attributes in the variable declaration, enclosed
 in brackets and separated by commas (if specifying more than one
 attribute).

 The brackets may occur in either of two places:

     1.  An attribute in brackets after a variable identifier in a VAR
         section applies to that variable only.

     2.  An attribute in brackets after the reserved word VAR applies to all
         of the variables in the section.

 Examples that specify variable attributes:

      VAR A, B, C [EXTERN] : INTEGER;
      {Applies to C only.}

      VAR [PUBLIC] A, B, C  : INTEGER;
      {Applies to A, B, and C.}

      VAR [PUBLIC] A, B, C [ORIGIN 16 1000] : INTEGER;
      {A, B, and C are all PUBLIC. ORIGIN of C}
      {is the absolute hexadecimal address 1000.}


 11.5.1  The STATIC Attribute


 The STATIC attribute gives a variable a unique, fixed location in
 memory.  This is in contrast to a procedure or function variable that
 is allocated on the stack or one that is dynamically allocated on the heap.
 Use of STATIC variables can save time and code space, but increases data
 space.

 All variables at the program, module, or unit level are automatically
 assigned a fixed memory location and given the STATIC attribute.

 Functions and procedures that use STATIC variables can execute
 recursively, but STATIC variables must be used only for data common to
 all invocations.  Since most of the other variable attributes imply the
 STATIC attribute, the trade-off between savings in time and code space or
 reduced data space applies to the PUBLIC, EXTERN, ORIGIN, and PORT
 attributes as well.

 Files declared in a procedure or function with the STATIC attribute
 are initialized when the routine is entered; they are closed when the
 routine terminates like other files. However, other STATIC variables are
 only initialized before program execution. This means that, except for open
 FILE variables, STATIC variables can be used to retain values between
 invocations of a procedure or function.

 Examples of STATIC variable declarations:

      VAR VECTOR [STATIC] : ARRAY [0..MAXVEC] OF INTEGER;
      VAR [STATIC] I, J, K : 0..MAXVEC;

 The STATIC attribute does not apply to procedures or functions, as do some
 other attributes.


 11.5.2  The PUBLIC and EXTERN Attributes


 The PUBLIC attribute indicates a variable that may be accessed by other
 loaded modules; the EXTERN attribute identifies a variable that resides in
 some other loaded module.  The identifier is passed to the target linker in
 the generated code object file (where it may be truncated if the linker
 imposes a length restriction).

 Variables given the PUBLIC or EXTERN attribute are implicitly STATIC.

 Examples of PUBLIC and EXTERN variable declarations:

      VAR [EXTERN] GLOBE1, GLOBE2 : INTEGER;
      {The variables GLOBE1 and GLOBE2 are declared}
      {EXTERN, meaning that they must be declared}
      {PUBLIC in some other loaded module.}

      VAR BASE_PAGE [PUBLIC, ORIGIN #12FE] : BYTE;
      {The variable BASE_PAGE is located at 12FE,}
      {hexadecimal. Because it is also PUBLIC, it can}
      {be accessed from other loaded modules that}
      {declare BASE_PAGE with the EXTERN attribute.}

 PUBLIC variables are usually allocated by the compiler, unless you also
 give them an ORIGIN. Giving a variable both the PUBLIC and ORIGIN
 attributes tells the loader that a global name has an absolute address.
 PUBLIC cannot be combined with PORT.

 If both PUBLIC and ORIGIN are present, the compiler does not need the
 loader to resolve the address.  However, the identifier is still passed to
 the linker for use by other modules.

 EXTERN variables are not allocated by the compiler.  Nor do they have
 an ORIGIN, since giving both EXTERN and ORIGIN implies two different ways
 to access the variable.  The reserved word EXTERNAL is synonymous with
 EXTERN. This increases portability from other Pascals, since others
 commonly use one of the two.

 Variables in the interface of a unit are automatically given either
 the PUBLIC or EXTERN attribute.  If a program, module, or unit USES an
 interface, its variables are made EXTERN; if you compile the IMPLEMENTATION
 of the interface, its variables are made PUBLIC.


 11.5.3  The ORIGIN and PORT Attributes


 The ORIGIN attribute directs the compiler to locate a variable at a
 given memory address; the PORT attribute specifies some kind of I/O
 address. In either case, the address must be a constant of any ordinal
 type. I/O ports, interrupt vectors, operating system data, and other
 related data can be accessed with ORIGIN or PORT variables.

 Examples of ORIGIN and STATIC variable declarations:

      VAR KEYBOARDP [PORT 16#FFF2] : CHAR;
      VAR INTRVECT [ORIGIN 8#200] : WORD;

 Variables with ORIGIN or PORT attributes are implicitly STATIC.  Also, they
 inhibit common subexpression optimization.  For example, if GATE has the
 ORIGIN attribute, the two statements X := GATE; Y := GATE; access GATE
 twice in the order given, instead of using the first value for both
 assignments. This ensures correct operation if GATE is a memory-mapped
 input port. However, if GATE is passed as a reference parameter,
 references to the parameter may be optimized away. For this reason, PORT
 variables cannot be passed as reference parameters.

 ORIGIN and PORT variables are never allocated or initialized by the
 compiler. The associated address only indicates where the variable is
 found.  ORIGIN always implies a memory address, but the meaning of PORT
 varies with the implementation.

 In most implementations, I/O is assumed to be memory mapped, so PORT
 is just a synonym for ORIGIN. Other implementations use the machine's
 native input and output instructions. Still others call port input and
 output routines for every access.

 For more information on the PORT attribute, see Appendix B, "Version
 Specifics," in your Microsoft Pascal Compiler User's Guide.

 Giving the PORT and ORIGIN attributes in brackets immediately
 following the VAR keyword is ambiguous and generates an error during
 compilation. (It would be unclear to the compiler whether all variables
 following should be at the same address or whether addresses should be
 assigned sequentially.)

       VAR [ORIGIN 0] FIRST, SECOND : BYTE;  {ILLEGAL!}

 ORIGIN (but not PORT) permits a segmented address using "segment: offset"
 notation.

      VAR SEGVECT [ORIGIN 16#0001 : 16#FFFE] : WORD;

 Currently, a variable with a segmented ORIGIN cannot be used as the control
 variable in a FOR statement.


 11.5.4  The READONLY Attribute


 The READONLY attribute prevents assignments to a variable.  It also
 prevents the variable being passed as a VAR or VARS parameter.  Also, a
 READONLY variable cannot be read with a READ statement or used as a FOR
 control variable.  You may use READONLY with any of the other attributes.

 Examples of READONLY variable declarations:

      VAR INPORT [PORT 12, READONLY] : BYTE;
      {INPORT is a READONLY PORT variable.}

      VAR [READONLY] I, J [PUBLIC], K [EXTERN] : INTEGER;
      {I, J, and K are all READONLY;}
      {J is also PUBLIC; K is also EXTERN.}

 CONST and CONSTS parameters, as well as FOR loop control variables (while
 in the body of the loop), are automatically given the READONLY attribute.
 READONLY is the only variable attribute that does not imply STATIC
 allocation.  A variable that is both READONLY and either PUBLIC or EXTERN
 in one source file is not necessarily READONLY when used in another source
 file. The READONLY attribute does not apply to procedures and functions.


 11.5.5  Combining Attributes


 You may give a variable multiple attributes. Separate the attributes with
 commas and enclose the list in brackets, as shown:

      VAR [STATIC]
      X, Y, Z [ORIGIN #FFFE, READONLY] : INTEGER;

 In this example, Z is a STATIC, READONLY variable with an ORIGIN at
 hexadecimal FFFE. These rules apply when you are combining attributes:

     1.  If you give a variable the EXTERN attribute, you may not give it
         the PORT, ORIGIN, or PUBLIC attributes in the current compiland.

     2.  If you give a variable the PORT attribute, you may not give it the
         ORIGIN, PUBLIC, or EXTERN attributes at all.

     3.  If you give a variable the ORIGIN attribute, you may not give it
         the PORT or EXTERN attributes. However, you may combine ORIGIN with
         PUBLIC.

     4.  If you give a variable the PUBLIC attribute, you may not give it
         the PORT or EXTERN attributes. However, you may combine PUBLIC with
         ORIGIN.

     5.  You may use STATIC and READONLY with any other attributes.



 Chapter 12  Expressions

 

 12.1  Simple Type Expressions

 12.2  Boolean Expressions

 12.3  Set Expressions

 12.4  Function Designators

 12.5  Evaluating Expressions

 12.6  Other Features of Expressions

        12.6.1  The EVAL Procedure

        12.6.2  The RESULT Function

        12.6.3  The RETYPE Function



 Expressions are constructions that evaluate to values. Table 12.1
 illustrates a variety of expressions, which, if A = 1 and B = 2, evaluate
 to the value shown.


          Table 12.1
          Expressions
ķ
          Expression                Value
          
          2                         2

          A                         1

          A + 2                     3

          (A + 2)                   3

          (A + 2) * (B - 3)        -3

 The operands in an expression may be a value or any other expression.
 When any operator is applied to an expression, that expression is called an
 operand.  With parentheses for grouping and operators that use other
 expressions, you can construct expressions as long and complicated as
 desired.

 The available operators, in the order in which they are applied, are
 as follows:

     1.  Unary

         NOT  [ADR ADS]

     2.  Multiplying

         * / DIV MOD AND (ISR SHL SHR)

     3.  Adding

         + - OR (XOR)

     4.  Relational

         =  <>  <=  >=  < > IN

 Operators shown above in parentheses are available only at the extend
 level of Microsoft Pascal, those in brackets only at the system level.

 A standard Pascal expression is either a value or the result of
 applying an operator to one or two values. Although a value can be of
 almost any type, most MS-Pascal operators only apply to the following
 types:

      INTEGER     INTEGER4
      WORD        BOOLEAN
      REAL        SET

 The relational operators also apply for the CHAR, enumerated, string,
 and reference types. For all operators (except the set operator IN),
 operands must have compatible types.


 12.1  Simple Type Expressions


 As a rule, the operands and the value resulting from an operation are
 all of the same type. Occasionally, however, the type of an operand is
 changed to the type required by an operator.

 This conversion occurs on two levels: one for constant operands only,
 and one for all operands. INTEGER to WORD conversion occurs for constant
 operands only; conversion from INTEGER to REAL and from INTEGER or WORD to
 INTEGER4 occurs for all operands.

 If necessary in constant expressions, INTEGER values change to WORD
 type. Be careful when mixing INTEGER and WORD constants in expressions.
 For example, if CBASE is the constant 16#C000 and DELTA is the constant -1,
 the following expression gives a WORD overflow:

      WRD (CBASE) + DELTA

 The overflow occurs because DELTA is converted to the WORD value 16#FFFF,
 and 16#C000 plus 16#FFFF is greater than MAXWORD. However, the following
 would work:

      WRD (ORD (CBASE) + DELTA)

 This expression gives the INTEGER value -16385, which changes to WORD
 16#BFFF. If conversion is needed by an operator or for an assignment, the
 compiler makes the following conversions:

     1.  from INTEGER to REAL or INTEGER4

     2.  from WORD to INTEGER4

 The following rules determine the type of the result of an expression
 involving these simple types:

     1.  +  -  *

         These operators affect INTEGERs, REALs, WORDs, and INTEGER4s,
         as shown in the following examples:

         +123
         A + 123
         -23.4
         A - 8
         A * B * 3

         Mixtures of REALs with INTEGERs and  of INTEGER4s with INTEGERs or
         WORDs are allowed. Where both operands are of the same type, the
         resulting type is the type of the operands. If either operand is
         REAL, the resulting type is REAL; otherwise, if either operand is
         INTEGER4, the resulting type is INTEGER4.

         Unary plus (+) and minus (-) are supported, along with the binary
         forms. Unary minus on a WORD type is two's complement (NOT is
         one's complement); since there are no negative WORD values, this
         always generates a warning.

         Because unary minus has the same precedence level as the adding
         operators:

            (X * -1)      {Is illegal}
            (-256 AND X)  {Is interpreted as -(256 AND X)}

     2.  /

         This is a "true" division operator. The result is always REAL.
         Operands may be INTEGER or REAL (not WORD or INTEGER4).

         Examples of division:

            34 / 26.4  =  1.28787...
            18 / 6     =  3.00000...

     3.  DIV   MOD

         These are the operators for integer divide quotient and remainder,
         respectively.  The left operand (dividend) is divided by the right
         operand (divisor).

         Examples of integer division:

            123 MOD  5 =  3
           -123 MOD  5 = -3  {Sign of result is}
                             {sign of dividend }
            123 MOD -5 =  3
            1.3 MOD  5       {Illegal with REAL operands}
            123 DIV  5 = 24
            1.3 DIV  5       {Illegal with REAL operands}

         Both operands must be of the same type: INTEGER, WORD, or INTEGER4
         (not REAL). The sign of the remainder (MOD) is always the sign of
         the dividend.

         MS-Pascal differs from the current draft ISO standard with respect
         to the semantics for DIV and MOD with negative operands, but the
         resulting code is more efficient. Programs intended to be portable
         should not use DIV and MOD unless both operands are positive.

     4.  AND   OR   XOR   NOT

         These extend level operators are bitwise logical functions.
         Operands must be INTEGER or WORD or INTEGER4 (never a mixture), and
         cannot be REAL. The result has the type of the operands.

         NOT is a bitwise one's complement operation on the single operand.
         If an INTEGER variable V has the value MAXINT, NOT V gives the
         illegal INTEGER value -32768. This generates an error if the
         initialization switch is on and the value is used later in a
         program.

         Given the following initial INTEGER values,

         X = 2#1111000011110000
         Y = 2#1111111100000000

         AND, OR, XOR, and NOT perform the following functions:

         X AND Y    1111000011110000
                    1111111100000000
                    ----------------
                    1111000000000000

         X OR Y     1111000011110000
                    1111111100000000
                    ----------------
                    1111111111110000

         X XOR Y    1111000011110000
                    1111111100000000
                    ----------------
                    0000111111110000

         NOT X      1111000011110000
                    ----------------
                    0000111100001111

     5.  SHL   SHR   ISR

         These extend level operators provide bitwise shifting functions.

         SHL and SHR are logical shifts left and right. ISR is an integer
         (signed) arithmetic shift right: the sign bit is always propagated,
         even on a WORD type operand. Since the compiler cannot generate a
         simple right shift for INTEGER division (-1 DIV 2 would be
         incorrect) and division is a very time-consuming operation, SHR or
         ISR could be used instead of DIV where appropriate.

         Operands must be both INTEGER, both WORD, or both INTEGER4;
         they cannot be REAL. The result has the same type as the operands.

         The left operand is shifted, and the right operand is the shift
         count in bits. A shift count less than 0 or greater than 32
         produces undefined results and generates an error message if the
         range checking switch is on. Shifts never cause overflow errors;
         shifted bits are simply lost.

         Given that X = 2#1111111100000000, the shifting functions
         would perform the following operations:

         X         1111111100000000
         X SHL 1   1111111000000000
         X SHR 1   0111111110000000
         X ISR 1   1111111110000000 {sign extension}


 12.2  Boolean Expressions


 The Boolean operators at the standard level of MS-Pascal are:

      NOT              AND              OR
      =                <                >
      <>               <=               >=

 XOR is available at the extend and systems levels.

 You may also use P <> Q as an exclusive OR function. Since
 FALSE < TRUE, P <= Q denotes the Boolean operation "P implies Q."
 Furthermore, the Boolean operators AND and OR are not the same as
 the WORD and INTEGER operators of the same name that are bitwise
 logical functions. The Boolean AND and OR operators may or may not
 evaluate their operations. The following example illustrates the
 danger of assuming that they don't:

      WHILE (I <= MAX) AND (V [I] <> T) DO I := I + 1;

 If array V has an upper bound MAX, then the evaluation of V [I] for I > MAX
 is a runtime error. This evaluation may or may not take place. Sometimes
 both operands are evaluated during optimization, and sometimes the
 evaluation of one may cause the evaluation of the other to be skipped. In
 the latter case, either operand may be evaluated first.

 Instead, use the following construction:

      WHILE I <= MAX DO
         IF V [I] <> T THEN I := I + 1 ELSE BREAK;

 See Section 13.3.5, "Sequential Control," for information on using AND THEN
 and OR ELSE to handle situations, such as the previous example, where tests
 are examined sequentially.

 The relational operators produce a Boolean result. The types of the
 operands of a relational operator (except for IN) must be compatible.
 If they are not compatible, one must be REAL and the other compatible
 with INTEGER.

 Reference types can only be compared with = and <>. To compare an
 address type with one of the other relational operators, you must use
 address field notation, as shown:

      IF (A.R < B.R) THEN statement;

 Except for the string types STRING and LSTRING, you cannot compare files,
 arrays, and records as wholes. Two STRING types must have the same upper
 bound to be compared; two LSTRINGs may have different upper bounds.

 In LSTRING comparison, characters past the current length are ignored.
 If the current length of one LSTRING is less than the length of the other
 and all characters up to the length of the shorter are equal, the compiler
 assumes the shorter one is "less than" the longer one. However, two
 LSTRINGs are not considered equal unless all current characters are equal
 and their current lengths are equal.

 The six relational operators  =, <>, <=, >=, <, and > have their
 normal meaning when applied to numeric, enumerated, CHAR, or string
 operands. Section 12.3, "Set Expressions," discusses the meaning of these
 relational operators (along with the relational operator IN) when applied
 to sets. Since the relational operators in Boolean expressions have a
 lower precedence than AND and OR, the following is incorrect:

      IF I < 10 AND J = K THEN

 Instead, you must write:

      IF (I < 10) AND (J = K) THEN

 Also, you may not use the numeric types where a Boolean operand is called
 for. (Some other languages permit this.) For an integer I, the clause IF I
 THEN is illegal; you must use the following instead:

      IF I <> 0 THEN

 Note, however, that MS-Pascal does allow the following:

      $if I $then

 The inclusion of special NAN ("Not A Number") values means that a
 comparison between two real numbers can have a result other than less-than,
 equal, or greater-than. The numbers can be unordered, meaning one or both
 are NANs.  An unordered result is the same as "not equal, not less than,
 and not greater than." For example, if variables A or B are NAN values:

     1.  A < B is false.

     2.  A <= B is false.

     3.  A > B is false.

     4.  A >= B is false.

     5.  A = B is false.

     6.  A <> B is, however, true.

 REAL comparisons do not follow the same rules as other comparisons in
 many ways. A < B is not always the same as NOT (B <= A);  this prevents
 some optimizations otherwise done by the compiler. If A is a NAN, then
 A <> A is true; in fact, this is a good way to check for a NAN value.


 12.3  Set Expressions


 Table 12.2 shows the MS-Pascal operators that apply differently to sets
 than to other types of expressions.


      Table 12.2
      Set Operators
ķ
      Operator            Meaning in Set Operations
      
      +                   Set union
      -                   Set difference
      *                   Set intersection
      =                   Test set equality
      <>                  Test set inequality
      <= and >=           Test subset and superset
      < and  >            Test proper subset and superset
      IN                  Test set membership

 Any operand whose type is SET OF S, where S is a subrange of T, is
 treated as if it were SET OF T. (T is restricted to the range from 0 to
 255 or the equivalent ORD values.) Either both operands must be PACKED or
 neither must be PACKED, unless one operand is a constant or constructed
 set.

 With the IN operator, the left operand (an ordinal) must be compatible
 with the base type of the right operand (a set). The expression X IN B
 is TRUE if X is a member of the set B, and FALSE otherwise. X can be
 outside of the range of the base type of B legally. For example, X IN B
 is always false if the following statements are true:

      X = 1
      B = SET OF 2..9

 (1 is compatible, but not assignment compatible, with 2..9).

 Angle brackets are set operators only at the extend level of MS-Pascal,
 since the ISO standard does not support them for sets. They test that
 a set is a proper subset or superset of another set. Proper subsetting
 does not permit a set as a subset if the two sets are equal.

 Expressions involving sets may use the "set constructor," which gives
 the elements in a set enclosed in square brackets. Each element can be
 an expression whose type is in the base type of the set or the lower
 and upper bounds of a range of elements in the base type. Elements cannot
 be sets themselves.

 Examples of sets involving set constructors:

      SET_COLOR := [RED, BLUE..PURPLE] - [YELLOW]
      SET_NUMBER :=
         [12, J+K, TRUNC (EXP (X))..TRUNC (EXP (X+1))]

 Set constructor syntax is similar to CASE constant syntax. If X > Y then
 [X..Y] denotes the empty set. Empty brackets also denote the empty set and
 are compatible with all sets. Also, if all elements are constant, a set
 constructor is the same as a set constant.

 Like other structured constants, the type identifier for a constant
 set can be included in a set constant, as in COLORSET [RED..BLUE]. This
 does not mean that a set constructor with variable elements can be given a
 type in an expression: NUMBERSET [I..J] is illegal if I or J is a
 variable.

 A set constructor such as [I, J,..K] or an untyped set such as [1,
 5..7], is compatible with either a PACKED or an unpacked set. A typed set
 constant, such as DIGITS [1, 5..7], is only compatible with sets that are
 PACKED or unpacked, respectively, in the same way as the explicit type of
 the constant.


 12.4  Function Designators


 A function designator specifies the activation of a function. It
 consists of the function identifier, followed by a (possibly empty)
 list of "actual parameters" in parentheses:

      {Declaration of the function ADD.}
      FUNCTION ADD (A, B : INTEGER); INTEGER;
        .
        .
      {Use of the function ADD in an expression.}
      X := ADD (7, X * 4) + 123;
      {ADD is a function designator.}

 These actual parameters substitute, position for position, for their
 corresponding "formal parameters," defined in the function declaration.

 Parameters can be variables, expressions, procedures, or functions.
 If the parameter list is empty, the parentheses must be omitted. See
 Section 14.4, "Procedure and Function Parameters," for more information
 on parameters.

 The order of evaluation and binding of the actual parameters varies,
 depending on the optimizations used. If the $simple metacommand is on, the
 order is left to right.

 In most computer languages, functions have two different uses:

     1.  In the mathematical sense, they take one or more values from a
         domain to produce a resulting value in a range. In this case, if
         the function never does anything else (such as assign to a global
         variable or do input/output), it is called a "pure" function.

     2.  The second type of function may have side effects, such as changing
         a static variable or a file. Functions of this second kind are
         said to be "impure."

 At the standard level, a function may return either a simple type or a
 pointer. At the extend level, a function can return any assignable type
 (i.e., any type except a file or super array).

 At the standard level, a pointer returned by a function can only be
 compared, assigned, or passed as a value parameter. At the extend level,
 however, the usual selection syntax for reference types, arrays, and
 records is allowed, following the function designator. See Section 11.4,
 "Using Variables and Values," for more information.

 Examples of function designators:

      SIN (X + Y)

      NEXTCHAR

      NEXTREC (17)^
      {Here the function return type}
      {is a pointer, and the returned}
      {pointer value is dereferenced.}

      NAD.NAME [1]
      {Here the function has no parameters.}
      {The return type is a record, one}
      {field of which is an array.}
      {The identifier for that field is}
      {NAME. The example above selects}
      {the first array component of the}
      {returned record.}

 It is more efficient to return a component of a structure than to
 return a structure and then use only one component of it. The compiler
 treats a function that returns a structure like a procedure, with an extra
 VAR parameter representing the result of the function. The function's
 caller allocates an unseen variable (on the stack) to receive the return
 value, but this "variable" is only allocated during execution of the
 statement that contains the function invocation.


 12.5  Evaluating Expressions


 In cases of ambiguity, an operator at a higher level is applied before
 one at a lower level. For instance, the following expression evaluates to
 7 and not to 9:

      1 + 2 * 3

 Use parentheses to change operator precedence. Thus, the following
 evaluates to 9 rather than 7:

      (1 + 2) * 3

 If the $simple switch is on, sequences of operators of the same
 precedence are executed from left to right. If the switch is off, the
 compiler may rearrange expressions and evaluate common subexpressions only
 once, in order to generate optimized code. The semantics of the precedence
 relationships are retained, but normal associative and distributive laws
 are used. For example,

      X * 3 + 12

 is an optimization of:

      3 * (6 + (X - 2))

 These optimizations may occasionally give you unexpected overflow errors.
 For example,

      (I - 100) + (J - 100)

 will be optimized into the following:

      (I + J) - 200

 This may result in an overflow error, although the original expression did
 not (e.g., if "I" and "J" were each 16400).

 An expression in your source file may or may not actually be evaluated
 when the program runs. For example, the expression F(X + Y) * 0 is always
 zero, so the subexpression (X + Y) and the function call need not be
 executed.

 The compiler does not optimize real expressions as much as, for
 example, integer expressions, to make sure that the result of a real
 expression is always what a simple evaluation of the expression, as given,
 would be. For example, the integer expression

      ((1 + I) - 1) * J

 is optimized to:

      I * J

 but the same expression with real variables is not optimized since the
 results may be different due to precision loss. Common subexpressions, such
 as 2 * X in SIN (2 * X) * COS (2 * X), may still be calculated just once
 and reloaded as necessary, but they are saved in a special 80-bit
 intermediate precision.

 The order of evaluation may be fixed by parentheses:

      (A + B) + C

 is evaluated by adding A and B first, but

      A + B + C

 may be evaluated by adding A and B, B and C, or even A and C first.

 Any expression can be passed as a CONST or CONSTS parameter or have
 its "address" found. The expression is calculated and stored in a temporary
 variable on the stack, and the address of this temporary variable can be
 used as a reference parameter or in some other address context.

 To avoid ambiguities, enclose such an expression with operators or
 function calls in parentheses. For example, to invoke a procedure
 FOO (CONST X, Y : INTEGER), FOO (I, (J + 14)) must be used instead
 of FOO (I, J + 14).

 This implies a subtle distinction in the case of functions. For
 example:

      FUNCTION SUM (CONST A, B : INTEGER) : INTEGER;
      BEGIN
        SUM := A;
        IF B <> 0 THEN
            SUM := SUM (SUM, (SUM (B, 0) - 1)) + 1;
      END;

 In this example, SUM is called recursively, subtracting one from B until B
 is zero.

 The use of a function identifier in a WITH statement follows a similar
 rule. For example, given a parameterless function, COMPLEX, which returns a
 record, "WITH COMPLEX" means "WITH the current value of the function."
 This can only occur inside the COMPLEX function itself. However, "WITH
 (COMPLEX)" causes the function to be called and the result assigned to a
 temporary local variable.

 Another way to describe this is to distinguish between "address" and
 "value" phrases. The left-hand side of an assignment, a reference
 parameter, the ADR and ADS operators, and the WITH statement all need an
 address. The right-hand side of an assignment and a value parameter all
 need a value.

 If an address is needed but only a value, such as a constant or an
 expression in parentheses, is available, the value must be put into memory
 so it has an address. For constants, the value goes in static memory;  for
 expressions, the value goes in stack (local) memory. A function identifier
 refers to the current value of the function as an address, but causes the
 function to be called as a value.

 Finally, in the scope of a function, the intrinsic procedure RESULT
 permits a reference to the current value of a function instead of invoking
 it recursively. For a function F, this means ADR F and ADR RESULT (F) are
 the same:  the address of the current value of F.  RESULT forces use of the
 current value in the same way that putting the function in parentheses, as
 in (F(X)), forces evaluation of the function.


 12.6  Other Features of Expressions


 EVAL and RESULT are two procedures available at the extend level for
 use with expressions. EVAL obtains the effect of a procedure from a
 function; RESULT yields the current value of a function within a function
 or nested procedure or function.

 At the system level, the function RETYPE allows you to change the type
 of a value.


 12.6.1  The EVAL Procedure


 EVAL evaluates its parameters without actually calling anything.
 Generally, you use EVAL to obtain the effect of a procedure from a
 function. In such cases, the values returned by functions are of no
 interest, so EVAL is only useful for functions with side effects. For
 example, a function that advances to the next item and also returns the
 item might be called in EVAL just to advance to the next item, since there
 is no need to obtain a function return value.

 Examples of the EVAL procedure:

      EVAL (NEXTLABEL (TRUE))
      EVAL (SIDEFUNC (X, Y), INDEX (4), COUNT)


 12.6.2  The RESULT Function


 Within the scope of a function, the intrinsic procedure RESULT permits a
 reference to the current value of a function instead of invoking it
 recursively. For a function F, this means ADR F and ADR RESULT (F) are the
 same; that is, the address of the current value of F. RESULT forces use of
 the current value in the same way that putting the function in parentheses
 as in (F (X)) forces evaluation of the function.

 Examples of the RESULT function:

      FUNCTION FACTORIAL (I : INTEGER) : INTEGER;
      BEGIN
        FACTORIAL := 1;  WHILE I > 1 DO
        BEGIN
          FACTORIAL := I * RESULT (FACTORIAL);
          I := I - 1
        END
      END;

     FUNCTION ABSVAL (I : INTEGER) : INTEGER;
     BEGIN
       ABSVAL := I;
       IF I < 0 THEN ABSVAL := -RESULT (ABSVAL)
     END;


 12.6.3  The RETYPE Function


 Occasionally, you need to change the type of a value.  You can do this with
 the RETYPE function, available at the system level of MS-Pascal. If the new
 type is a structure, RETYPE can be followed by the usual selection syntax.

 Examples of the RETYPE function:

      RETYPE (COLOR, 3)   {inverse of ORD}
      RETYPE (STRING2, I * J + K) [2]   {effect may vary}

 You must use RETYPE with caution: it works on the memory byte level and
 ignores whether the low order byte of a two-byte number comes first or
 second in memory.



 Chapter 13  Statements

 

 13.1  The Syntax of Pascal Statements

        13.1.1  Labels

        13.1.2  Separating Statements

        13.1.3  The Reserved Words BEGIN and END

 13.2  Simple Statements

        13.2.1  Assignment Statements

        13.2.2  Procedure Statements

        13.2.3  The GOTO Statement

        13.2.4  The BREAK, CYCLE, and RETURN Statements

 13.3  Structured Statements

        13.3.1  Compound Statements

        13.3.2  Conditional Statements

                 13.3.2.1  The IF Statement

                 13.3.2.2  The CASE Statement

        13.3.3  Repetition Statements

                 13.3.3.1  The WHILE Statement

                 13.3.3.2  The REPEAT Statement

                 13.3.3.3  The FOR Statement

                 13.3.3.4  The BREAK and CYCLE Statements

        13.3.4  The WITH Statement

        13.3.5  Sequential Control



 The body of a program, procedure, or function contains statements.
 Statements denote actions that the program can execute. This chapter first
 discusses the syntax of statements and then separates and describes two
 categories of statements: simple statements and structured statements. A
 simple statement has no parts that are themselves other statements; a
 structured statement consists of two or more other statements. Table 13.1
 lists the statements in each category in Microsoft Pascal.


          Table 13.1
          Microsoft Pascal Statement
ķ
          Simple                   Structured
          
          Assignment (:=)          Compound
          Procedure                IF/THEN/ELSE
          GOTO                     CASE
          BREAK                    FOR
          CYCLE                    WHILE
          RETURN                   REPEAT
          Empty                    WITH


 13.1  The Syntax of Pascal Statements


 Pascal statements are separated by a semicolon (;) and enclosed by reserved
 words such as BEGIN and END. A statement begins, optionally, with a label.
 Each of these three elements of statement syntax are discussed in the
 following sections.


 13.1.1  Labels


 Any statement referred to by a GOTO statement must have a label. A label
 at the standard level is one or more digits; leading zeros are ignored.
 Constant identifiers, expressions, and nondecimal notation cannot serve as
 labels.

 All labels must be declared in a LABEL section. At the extend level, a
 label can also be an identifier.

 Example using labels and GOTO statements:

      PROGRAM LOOPS (INPUT, OUTPUT);
      LABEL 1, HAWAII, MAINLAND;

      BEGIN
        MAINLAND : GOTO 1;
        HAWAII : WRITELN ('Here I am in Hawaii');
        1 : GOTO HAWAII
      END.

 A loop label is any label immediately preceding a looping statement:
 WHILE, REPEAT, or FOR. At the extend level, a BREAK or CYCLE statement
 can also refer to a loop label.

 Both a CASE constant list and a GOTO label may precede a statement, in
 which case the CASE constants come first and then the GOTO label. In the
 following example, 321 is a CASE value, 123 is a label:

      321 : 123 : IF LOOP THEN GOTO 123


 13.1.2  Separating Statements


 Semicolons separate statements. Semicolons do not terminate statements.
 However, since Pascal permits the empty statement, using the semicolon as
 if it were a statement terminator is rarely disastrous.

 Example showing semicolon to separate statements:

      BEGIN
         10 : WRITELN;
         A := 2 + 3;
         GOTO 10
      END

 A common error is to terminate the THEN clause in an IF/THEN/ELSE statement
 with a semicolon. Thus, the following example generates a warning message:

      IF A = 2 THEN WRITELN;
      ELSE A = 3

 Another common error is to put a semicolon after the DO in a WHILE or FOR
 statement:

     FOR I := 1 TO 10 DO;
     BEGIN
       A[I] := I;
       B[I] := 10 - I
     END;

 The previous example, as written, will "execute" an empty statement ten
 times, then execute the array assignments once. Since there are
 occasionally legitimate uses for repeating an empty statement, no
 warning is given when this occurs.

 The semicolon also follows the reserved word END at the close of a
 block of program statements.


 13.1.3  The Reserved Words BEGIN and END


 Whenever you want a program to execute a group of statements, instead
 of a single simple statement, you may enclose the block with the reserved
 words BEGIN and END.

 For example, the following group of statements between BEGIN and END
 will all be executed if the condition in the IF statement is TRUE:

      IF (MAX > 10) THEN
      BEGIN
        MAX = 10;
        MIN = 0;
        WRITELN (MAX, MIN)
      END;
      WRITELN ('done')

 At the extend level, you may substitute a pair of square brackets for the
 pair of keywords BEGIN and END.


 13.2  Simple Statements


 A simple statement is one in which no part constitutes another
 statement. Simple statements in standard Pascal are:


     1.  the assignment statement

     2.  the procedure statement

     3.  the GOTO statement

     4.  the empty statement

 The empty statement contains no symbols and denotes no action. It
 is included in the definition of the language primarily to permit you to
 use a semicolon after the last in a group of statements enclosed between
 BEGIN and END.

 The extend level in MS-Pascal adds three simple statements: BREAK,
 CYCLE, and RETURN.


 13.2.1  Assignment Statements


 The assignment statement replaces the current value of a variable with
 a new value, which you specify as an expression. Assignment is denoted
 by an adjacent colon and equal sign character (:=).

 Examples of assignment statements:

      A := B

      A[I] := 12 * 4 + (B * C)

      X : = Y
      {Illegal. Colon (:) and equal}
      {sign (=) must be adjacent.}

      A + 2 := B
      {Illegal. A + 2 is not a variable.}

      A := ADD (1,1)

 The value of the expression must be assignment compatible with the type of
 the variable. Selection of the variable may involve indexing an array or
 dereferencing a pointer or address. If it does, the compiler may,
 depending on the optimizations performed, mix these actions with the
 evaluation of the expression. If the $simple metacommand is on, the
 expression is evaluated first.

 An assignment to a nonlocal variable (including a function return)
 puts an equal sign (=) or percent sign (%) in the G column of the listing
 file.  See Section 18.5, "Listing File Format," for more information about
 these and other symbols used in the listing.

 Within the block of a function, an assignment to the identifier of the
 function sets the value returned by the function. The assignment to a
 function identifier may occur either within the actual body of the function
 or in the body of a procedure or function nested within it.

 If the range checking switch is on, an assignment to a set, subrange,
 or LSTRING variable may imply a runtime call to the error checking code.

 According to the MS-Pascal optimizer, each section of code without
 a label or other point that could receive control is eligible for
 rearrangement and common subexpression elimination. Naturally, the order
 of execution is retained when necessary.

 Given these statements,

     X := A + C + B;
     Y := A + B;
     Z := A

 the compiler might generate code to perform the following operations:

     1.  Get the value of A and save it.

     2.  Add the value of B and save the result.

     3.  Add the value of C and assign it to X.

     4.  Assign the saved A + B value to Y.

     5.  Assign the saved A value to Z.

 This optimization occurs only if assignment to X and Y and getting the
 value of A, B, or C are all independent. If C is a function without the
 PURE attribute and A is a global variable, evaluating C might change A.
 Then since the order of evaluation within an expression in this case is not
 fixed, the value of A in the first assignment could be the old value or the
 new one.

 However, since the order of evaluation among statements is fixed, the
 value of A in the second and third assignments is the new value.

 The following actions may limit the ability of the optimizer to find
 common subexpressions:

     1.  assignment to a nonlocal variable

     2.  assignment to a reference parameter

     3.  assignment to the referent of a pointer

     4.  assignment to the referent of an address variable

     5.  calling a procedure

     6.  calling a function without the PURE attribute

 The optimizer does allow for "aliases," that is, a single variable with
 two identifiers, perhaps one as a global variable and one as a reference
 parameter.


 13.2.2  Procedure Statements


 A procedure statement executes the procedure denoted by the procedure
 identifier.

 For example, assume you have defined the procedure DO_IT:

      PROCEDURE DO_IT;
      BEGIN
        WRITELN('Did it')
      END;

 DO_IT is now a statement that can be executed simply by invoking its name:

      DO_IT

 If you declare the procedure with a formal parameter list, the
 procedure statement must include the actual parameters.

 MS-Pascal includes a large number of predeclared procedures. See
 Chapter 15, "Available Procedures and Functions," for complete information.
 One of the predeclared procedures is ASSIGN. You need not declare it in
 order to use it.

      ASSIGN (INFILE, 'MYFILE')

 Note that the ASSIGN procedure contains a parameter list. These
 parameters are the actual parameters that are bound to the formal
 parameters in the procedure declaration. For a discussion of formal and
 reference parameters, see Section 14.4, "Procedure and Function
 Parameters."


 13.2.3  The GOTO Statement


 A GOTO statement indicates that further processing continues at another
 part of the program text, namely at the place of the label. You must
 declare a LABEL in a LABEL declaration section, before using it in a GOTO
 statement.

 Several restrictions apply to the use of GOTO statements:

     1.  A GOTO must not jump to a more deeply nested statement, that is,
         into an IF, CASE, WHILE, REPEAT, FOR, or WITH statement. GOTOs
         from one branch of an IF or CASE statement to another are
         permitted.

     2.  A GOTO from one procedure or function to a label in the main
         program or in a higher level procedure or function is permitted. A
         GOTO may jump out of one of these statements, so long as the
         statement is directly within the body of the procedure or function.
         However, such a jump generates extra code both at the location of
         the GOTO and at the location of the label. The GOTO and label must
         be in the same compiland, since labels, unlike variables, cannot be
         given the PUBLIC attribute.

 Examples of GOTO statements, both legal and illegal:

      PROGRAM LABEL_EXAMPLES;
      LABEL 1, 2, 3, 4;

        PROCEDURE ONE;
        LABEL 11, 12, 13;

          PROCEDURE IN_ONE;
          LABEL 21;
          {Outer level GOTOs cannot jump in to 21.}

          BEGIN
            IF TUESDAY THEN GOTO 1
            ELSE GOTO 11;
            {1 and 11 are both legal outer level labels.}
            21 : WRITE ('IN_ONE')
          END;

        BEGIN   {Procedure one}
          IF RAINING THEN GOTO 1 ELSE GOTO 11;
          {This is legal.}
          11 : GOTO 21
          {Illegal. Cannot jump into inner level}
          {procedures.}
        END;

        PROCEDURE TWO;
        BEGIN
          GOTO 11
          {Illegal. Cannot jump into different procedure}
          {at same level.}
        END;

      BEGIN   {Main level}
        IF SEATTLE
        THEN
          BEGIN BEGIN
            GOTO 2;
            {OK to go to 2 at program level.}
            4 : WRITE ('here')
          END END
        ELSE GOTO 4;
        {OK to jump into THEN clause.}
        2 : GOTO 3;
        {Illegal. Cannot jump into REPEAT statement.}
        REPEAT
            WHILE MS_BYRON DO
              3 : GOTO 2
              {OK to jump out of loops.}
        UNTIL DATE;
        1 : GOTO 11
        {Illegal. Cannot jump into procedure from program.}
      END.

 If the $goto metacommand is on, every GOTO statement is flagged with a
 warning that reminds you that "GOTOs are considered harmful." This may be
 useful either in an educational environment or for finding all GOTOs in a
 program in order to locate a bug. The J (jumps) column of the listing file
 contains the following:

     1.  A plus (+) flags a GOTO to a label later in the listing.

     2.  A minus sign (-) marks a GOTO to a label already encountered in the
         listing.

     3.  An asterisk (*) flags a RETURN or a mixture of jumps.

 See Section 18.5, "Listing File Format," for details about the listing
 file.


 13.2.4  The BREAK, CYCLE, and RETURN Statements


 At the extend level, BREAK, CYCLE, and RETURN statements are allowed in
 addition to the simple statements already described. These statements
 perform the following functions:

     1.  BREAK exits the currently executing loop.

     2.  CYCLE exits the current iteration of a loop and starts the next
         iteration.

     3.  RETURN exits the current procedure, function, program, or
         implementation.

 All three statements are functionally equivalent to a GOTO
 statement.

     1.  A BREAK statement is a GOTO to the first statement after a
         repetitive statement.

     2.  A CYCLE statement is a GOTO to an implied empty statement after
         the body of a repetitive statement. This jump starts the next
         iteration of a loop. In either a WHILE or REPEAT statement, CYCLE
         performs the Boolean test in the WHILE or UNTIL clause before
         executing the statement again; in a FOR statement, CYCLE goes to
         the next value of the control variable.

     3.  A RETURN statement is a GOTO to an implied empty statement
         after the last statement in the current procedure or function
         or the body of a program or implementation.

 The J (jump) column in the listing file contains a plus sign (+) for a
 BREAK or GOTO statement, a minus sign (-) for a CYCLE or GOTO statement,
 and an asterisk  (*) for a RETURN statement or a mixture of jumps. See
 Section 18.5, "Listing File Format," for information about the listing
 file.

 BREAK and CYCLE have two forms, one with a loop label and one without.
 If you give a loop label, the label identifies the loop to exit or restart.
 If you don't give a label, the innermost loop is assumed, as shown in the
 following example:

      OUTER : FOR I := 1 TO N1 DO
        INNER : FOR J := 1 TO N2 DO
          IF A [I, J] = TARGET THEN BREAK OUTER;


 13.3  Structured Statements


 Structured statements are themselves composed of other statements.
 There are four kinds of structured statements:

     1.  compound statements

     2.  conditional statements

     3.  repetitive statements

     4.  WITH statements

 The control level is shown in the the C (control) column of the listing
 file. The value in the C column is incremented each time control passes to
 a nested statement; conversely, this value is decremented each time control
 passes back to the nesting statement. This helps you search for a missing
 or extra END in a program.


 13.3.1  Compound Statements


 The compound statement is a sequence of simple statements, enclosed by
 the reserved words BEGIN and END. The components of a compound statement
 execute in the same sequence as they appear in the source file.

 Examples of compound statements:

      BEGIN
         TEMP := A [I];
         A[I] := A [J];
         A [J] := TEMP
         {Semicolon not needed here.}
      END

      BEGIN
         OPEN_DOOR;
         LET_EM_IN;
         CLOSE_DOOR;
         {Semicolon signifies empty statement.}
      END

 All MS-Pascal conditional and repetitive control structures (except REPEAT)
 operate on a single statement, not on multiple statements with ending
 delimiters. In this context, BEGIN and END serve as punctuation, like
 semicolon, colon, or parentheses. If you prefer, you may substitute a pair
 of square brackets for the BEGIN and END pair of reserved words. Note
 that a right bracket (]) matches only a left bracket ([) (not a BEGIN,
 CASE, or RECORD). In other words, a right bracket is not a synonym for
 END.

 Brackets may not be used as synonyms for BEGIN and END to enclose the
 body of a program, implementation, procedure, or function; only BEGIN and
 END can be used for this purpose.

 Examples of brackets replacing BEGIN and END:

      IF FLAG THEN [X := 1; Y := -1]
      ELSE [X := -1; Y := 0];

      WHILE P.N <> NIL DO
         [Q := P;  P := P.N; DISPOSE (Q)];

      FUNCTION R2 (R : REAL) : REAL;
         [R2 := R * 2]
         {Illegal.}


 13.3.2  Conditional Statements


 A conditional statement selects for execution only one of its component
 statements. The conditional statements are the IF and CASE statements. Use
 the IF statement for one or two conditions, the CASE statement for multiple
 conditions.


 13.3.2.1  The IF Statement

 The IF statement allows for conditional execution of a statement. If
 the Boolean expression following the IF is true, the statement following
 the THEN is executed. If the Boolean expression following the IF is false,
 the statement following the ELSE, if present, is executed.

 Examples of IF statements:

      IF I > 0 THEN I := I - 1
      {No semicolon here.}
      ELSE I := I + 1

      IF (I <= TOP) AND (ARRI [I] <> TARGET) THEN
         I := I + 1

      IF I <= TOP THEN
         IF ARRI [I] <> TARGET THEN
            I := I + 1

      IF I = 1 THEN
         IF J = 1 THEN
            WRITELN('I equals J')
         ELSE
            WRITELN('DONE only if I = 1 and J <> 1')
            {This ELSE is paired with the most deeply}
            {nested IF.  Thus, the second WRITELN is}
            {executed only if I = 1 and J <> 1.}

      IF I = 1 THEN BEGIN
         IF J = 1 THEN WRITELN('I equals J')
         END
      ELSE
         WRITELN('DONE only if I <> 1')
           {Now the ELSE is paired with the first IF,}
           {since the second IF statement is}
           {bracketed by the BEGIN/END pair. Thus,}
           {the second WRITELN is executed if I <> 1.}

 A semicolon (;) preceding an ELSE is always incorrect. The compiler skips
 it during compilation and issues a warning message.

 The Boolean expression following an IF may include the sequential
 control operators described in Section 13.3.5, "Sequential Control," later
 in this chapter.


 13.3.2.2  The CASE Statement

 The CASE statement consists of an expression (called the CASE index)
 and a list of statements.  Each statement is preceded by a constant list,
 called a CASE constant list. The one statement executed is the one whose
 CASE constant list contains the current value of the CASE index. The CASE
 index and all constants must be of compatible, ordinal types.

 Examples of CASE statements:

      CASE OPERATOR OF
        PLUS : X := X + Y;
        MINUS : X := X - Y;
        TIMES: X := X * Y
      END
      {OPERATOR is the CASE index. PLUS, MINUS, and}
      {TIMES are CASE constants. In this instance,}
      {they are all of the values assumable by the}
      {enumerated variable, OPERATOR.}

      CASE NEXTCH OF
        'A'..'Z', '_' : IDENTIFIER;
        '+', '-', '*', '/' : OPERATOR;
        {Commas separate CASE constants}
        {and ranges of CASE constants.}
        OTHERWISE
          WRITE ('Unknown Character')
          {i.e., if any other character}
      END

 The CASE constant syntax is the same as for RECORD variant declarations.
 In standard Pascal, a CASE constant is one or more constants separated by
 commas. At the extend level, you may substitute a range of constants,
 such as 'A'..'Z', for a constant. No constant value can apply to more than
 one statement. The extend level also allows the CASE statement to end with
 an OTHERWISE clause. The OTHERWISE clause contains additional statements to
 be executed in the event that the CASE index value is not in the given
 set of CASE constant values. One of two things happens if the CASE index
 value is not in the set and no OTHERWISE clause is present:

     1.  If the range checking switch is on, a runtime error is generated.

     2.  If the range checking switch is off, the result is undefined (and
         may be catastrophic).

 In MS-Pascal, control does not automatically pass to the next
 executable statement as in UCSD Pascal and some other languages.
 If you want this effect, include an empty OTHERWISE clause.

 A semicolon (;) may appear after the final statement in the list, but
 is not required.  The compiler skips over a colon (:) after an OTHERWISE
 and issues a warning.

 Depending on optimization, the code generated by the compiler for a
 CASE statement may be either a "jump table" or series of comparisons (or
 both).  If it is a jump table, a jump to an arbitrary location in memory
 can occur if the control variable is out of range and the range checking
 switch is off.


 13.3.3  Repetition Statements


 Repetition statements specify repeated execution of a statement. In
 standard Pascal, these include the WHILE, REPEAT, and FOR statements.

 At the extend level in MS-Pascal, there are two additional statements,
 BREAK and CYCLE, for leaving or restarting the statements being repeated.
 These statements are functionally equivalent to a GOTO but easier to use.


 13.3.3.1  The WHILE Statement

 The WHILE statement repeats a statement zero or more times, until a
 Boolean expression becomes false.

 Examples of WHILE statements:

      WHILE P <> NIL DO P := NEXT (P)

      WHILE NOT MICKEY DO
         BEGIN
            NEXTMOUSE;
            MICE := MICE + 1
         END

 The Boolean expression in a WHILE statement may include the sequential
 control operators described in Section 13.3.5, "Sequential Control."

 Use WHILE if it is possible that no iterations of the loop may be
 necessary; use REPEAT where you expect that at least one iteration of the
 loop is required.


 13.3.3.2  The REPEAT Statement


 The REPEAT statement repeats a sequence of statements one or more
 times, until a Boolean expression becomes true.

 Examples of REPEAT statements:

      REPEAT
         READ (LINEBUFF);
         COUNT := COUNT + 1
      UNTIL EOF;

      REPEAT GAME UNTIL TIRED;


 The Boolean expression in a REPEAT statement may include the sequential
 control operators described in Section 13.3.5, "Sequential Control."

 Use the REPEAT statement to execute statements, not just a single
 statement, one or more times until a condition becomes true. This differs
 from the WHILE statement in which a single statement may not be executed at
 all.


 13.3.3.3  The FOR Statement

 The FOR statement tells the compiler to execute a statement repeatedly
 while a progression of values is assigned to a variable, called the control
 variable of the FOR statement. The values assigned start with a value
 called the initial value and end with one called the final value.

 The FOR statement has two forms, one where the control variable
 increases in value and one where the control variable decreases in value:

      FOR I := 1 TO 10 DO
      {I is the control variable.}
        SUM := SUM + VICTORVECTOR [I]

      FOR CH := 'Z' DOWNTO 'A' DO
      {CH is the control variable.}
        WRITE (CH)


 You may also use a FOR statement to step through the values of a set, as
 shown:

      FOR TINT :=
         LOWER (SHADES) TO UPPER (SHADES) DO
            IF TINT IN SHADES
            THEN PAINT_AREA (TINT);

 The ISO standard gives explicit rules regarding the control variable in FOR
 statements:

     1.  It must be of an ordinal type.

     2.  It must be an entire variable, not a component of a structure.

     3.  It must be local to the immediately enclosing program, procedure,
         or function and cannot be a reference parameter of the procedure or
         function.

         However, at the extend level of MS-Pascal, the control variable may
         also be any STATIC variable, such as a variable declared at the
         program level, unless the variable has a segmented ORIGIN
         attribute. Using a program level variable is an ISO error not
         caught.

     4.  No assignments to the control variable are allowed in the repeated
         statement. This error is caught by making the control variable
         READONLY within the FOR statement; it is not caught when a
         procedure or function invoked by the repeated statement alters the
         control variable. The control variable cannot be passed as a VAR
         (or VARS) parameter to a procedure or function.

     5.  The initial and final values of the control variable must be
         compatible with the type of the control variable. If the statement
         is executed, both the initial and final values must also be
         assignment compatible with the control variable. The initial value
         is always evaluated first, and then the final value. Both are
         evaluated only once before the statement executes.

 The statement following the DO is not executed at all if:

     1.  The initial value is greater than the final value in the TO case.

     2.  The initial value is less than the final value in the DOWNTO case.

 The sequence of values given the control variable starts with the initial
 value. This sequence is defined with the SUCC function for the TO case
 or the PRED function for the DOWNTO case until the last execution of
 the statement, when the control variable has its final value. The value of
 the control variable, after a FOR statement terminates naturally (whether
 or not the body executes), is undefined. It may vary due to optimization
 and, if $initck is on, may be set to an uninitialized value. However, the
 value of the control variable after leaving a FOR statement with GOTO or
 BREAK is defined as the value it had at the time of exit.

 In standard Pascal, the body of a FOR statement may or may not be
 executed, so a test is necessary to see whether the body should be executed
 at all.  However, if the control variable is of type WORD (or a subrange)
 and its initial value is a constant zero, the body must be executed no
 matter what the final value. In this case, no extra test need be executed
 and no code is generated to perform such a test.

 Also, a control variable with the STATIC attribute may be more
 efficient than one that is not.

 At the extend level in MS-Pascal, you may use temporary control
 variables:

      FOR VAR control-variable

 The prefix VAR causes the control variable to be declared local to
 the FOR statement (i.e., at a lower scope) and need not be declared in a
 VAR section. Such a control variable is not available outside the FOR
 statement, and any other variable with the same identifier is not available
 within the FOR statement itself. Other synonymous variables are, however,
 available to procedures or functions called within the FOR statement.

 Examples of temporary control variables:

      FOR VAR I := 1 TO 100 DO
         SUM := SUM + VICTOR [I]

      FOR VAR COUNTDOWN := 10 DOWNTO LIFT_OFF DO
         MONITOR_ROCKET



 13.3.3.4  The BREAK and CYCLE Statements

 In theory, a program using the MS-Pascal extend level BREAK and CYCLE
 statements does not need to use any GOTO statements.

 Each of these two statements has two forms, one with a loop label and
 one without. A loop label is a normal GOTO label prefixed to a FOR,
 WHILE, or REPEAT statement. Since, at the extend level, you may use
 identifier labels, a suggested practice is to use integers for labels
 referenced by GOTOs and identifiers for loop labels.

 Examples of CYCLE and BREAK statements:

      LABEL SEARCH, CLIMB;
        .
        .
      SEARCH : WHILE I <= I_TOP DO
        IF PILE [I] = TARGET THEN BREAK SEARCH
        ELSE I := I + 1;
        .
        .
      FOR I := 1 TO N DO
        IF NEXT [I] = NIL THEN BREAK;
        .
        .
      CLIMB : WHILE NOT ITEM^.LEAF DO
        BEGIN
          IF ITEM^.LEFT <> NIL
            THEN [ITEM := ITEM^.LEFT; CYCLE CLIMB];
          IF ITEM^.RIGHT <> NIL
            THEN [ITEM := ITEM^.RIGHT; CYCLE CLIMB];
          WRITELN ('Very strange node');
          BREAK CLIMB
        END;


 13.3.4  The WITH Statement


 The WITH statement opens the scope of a statement to include the fields
 of one or more records, so you can refer to the fields directly. For
 example, the following statements are equivalent:

     WITH PERSON DO WRITE (NAME, ADDRESS, PHONE)
     WRITE (PERSON.NAME, PERSON.ADDRESS, PERSON.PHONE)

 The record given may be a variable, constant identifier, structured
 constant, or function identifier; it may not be a component of a PACKED
 structure. If you use a function identifier, it refers to the function's
 local result variable. If the record given in a WITH statement is a file
 buffer variable, the compiler issues a warning, since changing the position
 in the WITH statement may cause an error.

 The record given can also be any expression in parentheses, in which
 case the expression is evaluated and the result assigned to a temporary
 (hidden) variable. If you want to evaluate a function designator, you must
 enclose it in parentheses.

 You may give a list of records after the WITH, separated by commas.
 Each record so listed must be of a different type from all the others,
 since the field identifiers refer only to the last instance of the record
 with the type. These statements are equivalent:

     WITH PMODE, QMODE DO statement
     WITH PMODE DO WITH QMODE DO statement

 Any record variable of a WITH statement that is a component of another
 variable is selected before the statement is executed. Active WITH
 variables should not be passed as VAR or VARS parameters, nor can their
 pointers be passed to the DISPOSE procedure. However, these errors are not
 caught by the compiler. Assignments to any of the record variables in the
 WITH list or components of these variables are allowed, as long as the WITH
 record is a variable.

 In MS-Pascal, every WITH statement allocates an address variable that
 holds the address of the record. If the record variable is on the heap, the
 pointer to it should not be DISPOSEd within the WITH statement. If the
 record variable is a file buffer, no I/O should be done to the file within
 the WITH statement. Avoid assignments to the WITH record itself in
 programs intended to be portable.


 13.3.5  Sequential Control


 To increase execution speed or guarantee correct evaluation, it is
 often useful in IF, WHILE, and REPEAT statements to treat the Boolean
 expression as a series of tests. If one test fails, the remaining tests are
 not executed. Two extend level operators in MS-Pascal provide for such
 tests:

     1.  AND THEN

        X AND THEN Y is false if X is false; Y is only evaluated if X
        is true.

     2.  OR ELSE

         X OR ELSE Y is true if X is true; Y is only evaluated if X is
         false.

 If you use several sequential control operators, the compiler evaluates
 them strictly from left to right.

 Examples of sequential control operators:

      IF SYM <> NIL AND THEN SYM^.VAL < 0 THEN
         NEXT_SYMBOL
      WHILE I <= MAX AND THEN VECT [I] <> KEY DO
         I := I + 1;

      REPEAT GEN (VAL)
      UNTIL VAL = 0 OR ELSE (QU DIV VAL) = 0;

      WHILE POOR AND THEN GETTING_POORER
         OR ELSE BROKE AND THEN BANKRUPT DO
            GET_RICH

 You may only include these operators in the Boolean expression of an IF,
 WHILE, or UNTIL clause; they may not be used in other Boolean expressions.
 Furthermore, they may not occur in parentheses and are evaluated after all
 other operators.



 Chapter 14  Introduction to Procedures and Functions

 

 14.1  Procedures

 14.2  Functions

 14.3  Attributes and Directives

        14.3.1  The FORWARD Directive

        14.3.2  The EXTERN  Directive

        14.3.3  The PUBLIC Attribute

        14.3.4  The ORIGIN Attribute

        14.3.5  The FORTRAN Attribute

        14.3.6  The INTERRUPT Attribute

        14.3.7  The PURE Attribute

 14.4  Procedure and Function Parameters

        14.4.1  Value Parameters

        14.4.2  Reference Parameters

                 14.4.2.1  Super Array Parameters

                 14.4.2.2  Constant and Segment Parameters

        14.4.3  Procedural and Functional Parameters



 Procedures and functions act as subprograms that execute under
 the supervision of a main program. Unlike programs, however, procedures and
 functions can be nested within each other and can even call themselves.
 Furthermore, they have sophisticated parameter passing capabilities that
 programs lack.

 Procedures are invoked as program statements; functions can be invoked
 in program statements wherever a value is called for.

 The general format for procedures and functions is similar to the
 format for programs. The three-part structure includes a heading,
 declarations, and a body.

 Example of a procedure declaration:

      {Heading}
      PROCEDURE MODEL (I : INTEGER; R : REAL);

      {Beginning of declaration section}
      LABEL 123;
      CONST ATOP = 199;
      TYPE INDEX = 0..ATOP;
      VAR ARAY : ARRAY [INDEX] OF REAL; J : INDEX;
      {Function declaration}
      FUNCTION FONE (RX : REAL) : REAL;
      BEGIN
         FONE := RX * I
      END;

      {Procedure declaration}
      PROCEDURE FOUT (RY : REAL);
      BEGIN
         WRITE ('Output is ', RY)
      END;

      {Body of procedure MODEL}
      BEGIN
        FOR J := 0 TO ATOP DO
          IF GLOBALVAR THEN
          {Activation of procedure FOUT with}
          {value returned by function FONE.}
               FOUT (FONE (R + ARAY [J]))
            ELSE GOTO 123;
        123:  WRITELN ('Done')
      END;

 The declarations and body together are called the block.

 The declaration of a procedure or function associates an identifier
 with a portion of a program. Later, you can activate that portion of the
 program with the appropriate procedure statement or function designator.


 14.1  Procedures


 The foregoing example illustrates the general format of a procedure
 declaration. The heading is followed by:

     1.  declarations for labels, constants, types, variables, and values

     2.  local procedures and functions

     3.  the body, which is enclosed by the reserved words BEGIN and END

 When the body of a procedure finishes execution, control returns to the
 program element that called it.

 At the standard level, the order of declarations must be as follows:

     1.  LABEL

     2.  CONST

     3.  TYPE

     4.  VAR

     5.  procedures and functions

 At the extend level, you may have any number of LABEL, CONST, TYPE,
 VAR, and VALUE sections, as well as procedure and function declarations, in
 any order.  Although data declarations (CONST, TYPE, VAR, VALUE) can be
 intermixed with procedure and function declarations, it is usually clearer
 to give all data declarations first.

 However, putting variable declarations after procedure and function
 declarations guarantees that these variables will not be used by any of the
 procedures or functions.

 In general, the initial values of variables are not defined.  The
 VALUE section, which should follow the VAR section, is an MS-Pascal
 extension that lets you explicitly initialize program, module,
 implementation, STATIC, and PUBLIC variables. If the initialization switch
 ($initck) is on, all INTEGER, INTEGER subrange, REAL, and pointer variables
 are set to an uninitialized value. File variables are always initialized,
 regardless of the setting of the initialization switch.


 14.2  Functions


 Functions are the same as procedures, except that they are invoked in
 an expression instead of a statement and they return a value.

 Function declarations define the parts of a program that compute a
 value. Functions are activated when a function designator, which is part of
 an expression, is evaluated.

 A function declaration has the same format as a procedure declaration,
 except that the heading also gives the type of value returned by the
 function.

 Example of a function heading:

      FUNCTION MAXIMUM (I, J : INTEGER) : INTEGER;

 Within the block of a function, either in the body itself or in a
 procedure or function nested within the block, at least one assignment to
 the function identifier must be executed to set the return value.  The
 compiler doesn't check for this assignment at runtime, unless the
 initialization switch is on and the returned type is INTEGER, REAL, or a
 pointer.  However, if there is no assignment at all to the function
 identifier, the compiler issues an error message.

 At the standard level, functions can return any simple type (ordinal,
 REAL, or INTEGER4) or a pointer.  At the extend level, functions can return
 any simple, structured, or reference type. However, they cannot return any
 type that cannot be assigned (i.e., a super array type or a structure
 containing a file, although a super array derived type is permitted).

 A function identifier in an expression invokes the function
 recursively, rather than giving the current value of the function.

 To obtain the current value, use the function RESULT, which takes the
 function identifier as a parameter and is available at the extend level.

 The following is an example of a RESULT function used to obtain the
 current value of a function within an expression:

     FUNCTION FACT (F : REAL) : REAL;
     BEGIN
       FACT := 1;
       WHILE F > 1 DO
          BEGIN
            FACT := RESULT (FACT) * F; F:= F - 1
          END
     END;

 Using the RESULT function is more efficient than using a separate
 local variable for the value of the function and then assigning this local
 variable to the function identifier before returning.  If the function has
 a structured value, the usual component selection syntax can follow the
 RESULT function.

 A function identifier on the left side of an assignment refers to the
 function's local variable, which contains its current value, instead of
 invoking the function recursively. Other places where using the function
 identifier refers to this local variable are the following:

     1.  a reference parameter

     2.  the record of a WITH statement

     3.  the operand of an ADR or ADS operator

 All of these uses involve getting the address (not the value) of a
 variable.

 Instead of using the function's local variable, you may want to invoke
 the function and use the return value. As mentioned in Section 11.1, "What
 Is a Variable?" getting the address of an expression involves evaluating
 the expression, putting the resulting value into a temporary (hidden)
 variable, and using the address of this variable.

 To do this for a function, you must force evaluation by putting the
 function designator in parentheses, as shown:

     TYPE IREC = RECORD I : INTEGER END;

     FUNCTION SUM (A, B : INTEGER) : IREC;
     {Return sum of A and B.}
     BEGIN
       IF TUESDAY THEN
       BEGIN                 {On Tuesdays, we recurse!}
         IF B = 0 THEN BEGIN SUM := A; RETURN END;
         WITH (SUM (A, B - 1))  {Call SUM recursively.}
           DO SUM.I := I + 1 {I is result of call.}
       END
       ELSE                  {Use function's}
         WITH SUM            {local variable.}
           DO I := A + B    {I is local variable.}
     END;


 14.3  Attributes and Directives


 An attribute gives additional information about a procedure or
 function. Attributes are available at the extend level of Microsoft
 Pascal. They are placed after the heading, enclosed in brackets, and
 separated by commas. Available attributes include ORIGIN, PUBLIC, FORTRAN,
 PURE, and INTERRUPT.

 A directive gives information about a procedure or function, but it
 also indicates that only the heading of the procedure or function occurs,
 by replacing the block (declarations and body) normally included after the
 heading. Directives are available in standard Pascal. EXTERN and FORWARD
 are the only directives available. EXTERN can only be used with procedures
 or functions directly nested in a program, module, implementation, or
 interface. This restriction prevents access to nonlocal stack variables.

 Table 14.1 displays the attributes and directives that apply to
 procedures and functions. Sections 14.3.1 through 14.3.7 describe these
 attributes and directives in detail.


 Table 14.1
 Attributes and Directives for Procedures and Functions
ķ
 Name           Purpose
 
 FORWARD        A directive. Lets you call a procedure or function before
                you give its block in the source file.

 EXTERN         A directive. Indicates that a procedure or function resides
 Name           Purpose
EXTERN         A directive. Indicates that a procedure or function resides
                in another loaded module.

 PUBLIC         An attribute. Indicates that a procedure or function may
                be accessed by other loaded modules.

 ORIGIN         An attribute. Tells the compiler where the code for an
                EXTERN procedure or function resides.

 FORTRAN        An attribute. Specifies a calling sequence for compatibility
                with Microsoft FORTRAN.

 INTERRUPT      An attribute. Gives a procedure a special calling sequence
                that saves program status on the stack.

 PURE           An attribute. Signifies that the function does not modify
                any global variables.

 The following rules apply when you combine attributes in the declaration of
 procedures and functions:

     1.  Any function may be given the PURE attribute.

     2.  Procedures and functions with attributes must be nested directly
         within a program, module, or unit. The only exception to this rule
         is the PURE attribute.

     3.  A given procedure or function may have only one calling sequence
         attribute (i.e., either FORTRAN or INTERRUPT, but not both).

     4.  PUBLIC and EXTERN are mutually exclusive, as are PUBLIC and ORIGIN.

 The EXTERN or FORWARD directive is given automatically to all
 constituents of the interface of a unit; in the implementation, PUBLIC is
 given automatically to all constituents that are not EXTERN.

 Since you declare the constituents of a unit only in the interface
 (not in the implementation), the interface is where you give the
 attributes.  You may give the EXTERN directive in an implementation by
 declaring all EXTERN procedures and functions first; you may not use ORIGIN
 in either the interface or implementation of a unit.

 In a module, you may give a group of attributes in the heading to
 apply to all directly nested procedures and functions.  The only exception
 to this rule is the ORIGIN attribute, which may apply only to a single
 procedure or function.

 If the PUBLIC attribute is one of a group of attributes in the heading
 of a module, an EXTERN attribute given to a procedure or function within
 the module explicitly overrides the global PUBLIC attribute. If the module
 heading has no attribute clause, the PUBLIC attribute is assumed for all
 directly nested procedures and functions.

 The PUBLIC attribute allows a procedure or function to be called by
 other loaded code, and cannot be used with the EXTERN directive. The
 EXTERN directive  permits a call to some other loaded code, using either
 the ORIGIN address or the linker. PUBLIC, EXTERN, and ORIGIN provide a low
 level way to link MS-Pascal routines with other routines in MS-Pascal or
 other languages.

 A procedure or function declaration with the EXTERN or FORWARD directive
 consists only of the heading, without an enclosed block. EXTERN
 routines have an implied block outside of the program. FORWARD routines are
 fully declared (have a block) later in the same compiland. Both directives
 are available at the standard level of MS-Pascal. The keyword EXTERNAL is
 a synonym for EXTERN.

 The PURE attribute applies only to functions, not to procedures.Conversely,
 INTERRUPT applies only to procedures, not to functions. PURE is the only
 attribute that can be used in nested functions.


 14.3.1  The FORWARD Directive


 A FORWARD declaration allows you to call a procedure or function before
 you fully declare it in the source text. This permits indirect recursion,
 where A calls B and B calls A. You make a FORWARD declaration by
 specifying a procedure or function heading, followed by the directive
 FORWARD. Later, you actually declare the procedure or function,
 without repeating the formal parameter list, attributes, or return types.

 Example of a FORWARD declaration:

      {Declaration of ALPHA, with parameter}
      {list and attributes}
      FUNCTION ALPHA (Q, R : REAL) : REAL [PUBLIC];
      FORWARD;

      {Call for ALPHA}
      PROCEDURE BETA (VAR S, T : REAL);
      BEGIN
        T := ALPHA (S, 3.14)
      END;

      {Actual declaration of ALPHA,}
      {without parameter list}
      FUNCTION ALPHA;
      BEGIN
        ALPHA := (Q + R);
        IF R < 0.0 THEN BETA (3.14, ALPHA)
      END;


 14.3.2  The EXTERN Directive


 The EXTERN directive identifies a procedure or function that resides in
 another loaded module. You give only the heading of the procedure or
 function, followed by the word EXTERN. The actual implementation of the
 procedure or function is presumed to exist in some other module.

 EXTERN is an attribute when used with a variable, but a directive when
 used with a procedure or function. As with variables, the keyword EXTERNAL
 is a synonym for EXTERN.

 The EXTERN directive for a particular procedure or function within a
 module overrides the PUBLIC attribute given for the entire module. The
 EXTERN directive is also permitted in an implementation of a unit for a
 constituent procedure or function. All such external constituents must be
 declared at the beginning of the implementation, before all other
 procedures and functions.

 Any procedure or function with the EXTERN directive must be directly
 nested within a program. You can also link MS-Pascal routines by linking
 separately compiled units. See Chapter 17, "Compilable Parts of a Program."

 Examples of procedure and function headings declared with the EXTERN
 directive:

      FUNCTION POWER (X, Y : REAL) : REAL; EXTERN;

      PROCEDURE ACCESS (KEY : KTYP) [ORIGIN SYSB + 4];
      EXTERN;

 In these examples, the function POWER is declared EXTERN, as is the
 procedure ACCESS. Both are implemented in external compilands. ACCESS also
 has the ORIGIN attribute, which is discussed later, in Section 14.3.4, "The
 ORIGIN Attribute."

 You may not declare a procedure or function EXTERN if you have previously
 declared it FORWARD.


 14.3.3  The PUBLIC Attribute


 The PUBLIC attribute indicates a procedure or function that you can
 access from other loaded modules. In general, you access PUBLIC procedures
 and functions from other loaded modules by declaring them EXTERN in the
 modules that call them. Thus, you declare a procedure PUBLIC and
 define it in one module, and use it in another simply by declaring it
 EXTERN in the other module.

 As with variables, the identifier of the procedure or function is
 passed to the linker, where it may be truncated if the linker requires it.
 See Appendix B, "Version Specifics," in your Microsoft Pascal Compiler
 User's Guide for specific information on limitations your version of the
 compiler and linker may set on identifiers. PUBLIC and ORIGIN are mutually
 exclusive; PUBLIC routines need a following block, and ORIGIN routines must
 be EXTERN.

 Any procedure or function with the PUBLIC attribute must be directly
 nested within a program or implementation. A higher level way to link MS-
 Pascal routines is by linking separately compiled units. See Chapter 17,
 "Compilable Parts of a Program," for details.

 Examples of procedures and functions declared PUBLIC:

      FUNCTION POWER (X, Y : REAL) : REAL [PUBLIC];
      {The function POWER is available to other modules}
      {because it has been declared PUBLIC.}
      BEGIN
        .
        .
      END;

      PROCEDURE ACCESS (KEY : KTYP)
      [ORIGIN SYSB + 4, PUBLIC];
      BEGIN
        .
        .
      END;
      {Illegal since ORIGIN must also be EXTERN.}


 14.3.4  The ORIGIN Attribute


 The ORIGIN attribute must be used with the EXTERN directive; ORIGIN tells
 the compiler where the procedure or function can be found directly, so
 the linker does not require a corresponding PUBLIC identifier.

 Examples of procedures and functions given the ORIGIN attribute:

      PROCEDURE OPSYS [ORIGIN 8, FORTRAN];
      EXTERN;

      FUNCTION A_TO_D (C : SINT) : SINT [ORIGIN #100];
      EXTERN;


 In the first example, the procedure OPSYS begins at the absolute
 decimal address 8, has the FORTRAN calling sequence (described in Section
 14.3.5, "The FORTRAN Attribute"), and is declared EXTERN. In the second
 example, the function A_TO_D takes a SINT value as a parameter (SINT is the
 predeclared integer subrange from -127 to +127). The function is located
 at the hexadecimal address 100.

 As with ORIGIN variables, the compiler uses the address to find the
 code and gives no directives to the linker. This permits, for example,
 calling routines at fixed addresses in ROM. In simple cases, it can
 substitute for a linking loader.

 Remember that ORIGIN always implies EXTERN. Thus, procedures or
 functions that have previously been declared FORWARD cannot be declared
 with the ORIGIN attribute. Nor may you give ORIGIN as an attribute after
 the module heading.

 Currently, you may not use the ORIGIN attribute with a constituent of
 a unit, either in an interface or in an implementation.

 As with variables, the origin can be a segmented address. On
 segmented machines, a nonsegmented procedural origin assumes the current
 code segment with the offset given with the attribute.


 14.3.5  The FORTRAN Attribute


 The FORTRAN attribute applies both to procedures and functions (but not
 to variables).  Instead of the usual Pascal calling sequence, it specifies
 a calling sequence that is compatible with the MS-FORTRAN compiler on your
 machine.  This lets you call an MS-Pascal procedure or function from
 MS-FORTRAN programs and, conversely, external FORTRAN subroutines or
 MS-FORTRAN functions from an MS-Pascal program.

 Example of a procedure with the FORTRAN attribute:

      PROCEDURE DELTA (I, J : INTEGER) [FORTRAN];
      FORWARD;

 Any procedure or function with the FORTRAN attribute must be nested
 directly within a program or implementation.

 In a 16-bit environment, MS-Pascal uses the same calling sequence as
 the compilers for Microsoft FORTRAN, Microsoft BASIC, and Microsoft COBOL.
 Thus, there is no need to give the FORTRAN attribute; if you do, it is
 ignored by the MS-Pascal Compiler.  See Appendix B, "Version Specifics," in
 your Microsoft Pascal Compiler User's Guide for details on the MS-Pascal
 calling sequence.


 14.3.6  The INTERRUPT Attribute


 The INTERRUPT attribute applies only to procedures (not to functions or
 variables). It gives a procedure a special calling sequence that saves
 program status on the stack, which in turn allows a hardware interrupt to
 be processed, status restored, and control returned to the program, all
 without affecting the current state of the program.

 Example of a procedure with the INTERRUPT attribute:

      PROCEDURE INCHAR [INTERRUPT];

 Because procedures with the INTERRUPT attribute are intended to be
 invoked by hardware interrupts, you may not invoke them with a procedure
 statement. An INTERRUPT procedure can only be invoked when the interrupt
 associated with it occurs. Furthermore, INTERRUPT procedures take no
 parameters.

 Declaring a procedure with the INTERRUPT attribute ensures that the
 procedure conforms to the constraints of an interrupt handler in which:

     1.  a special calling sequence saves all status on the stack

     2.  the status saved includes machine registers and flags, plus any
         special global compiler data such as the frame pointer

     3.  the saved status is restored upon exit from the procedure

 All INTERRUPT procedures must be nested directly within a compiland.

 Interrupts are not automatically vectored to INTERRUPT procedures;
 further, insofar as possible on the target machine, interrupts are neither
 enabled or disabled by an INTERRUPT procedure. Interrupt vectoring and
 enabling are too machine-dependent to be included in a machine-independent
 language like MS-Pascal.

 However, MS-Pascal does provide the VECTIN library procedure, which
 takes an interrupt level and an interrupt procedure as parameters and
 sets the interrupt vector in a machine-dependent way.

 Similarly,  the library procedures ENABIN and DISBIN, respectively,
 enable and disable interrupts in a machine-dependent way. See Chapter 15,
 " Available Procedures and Functions," for more information on these
 routines. See also Appendix B, "Version Specifics," in the Microsoft Pascal
 Compiler User's Guide for information about the implementation of these
 routines under your operating system.

 An INTERRUPT procedure should usually return normally, in order to
 continue processing in the interrupted routine. This means the following:

     1.  You should not execute a GOTO that leaves an INTERRUPT procedure.

     2.  All debug checking should be turned off ($debug-, $entry-, and
         $runtime-).

     3.  Stack overflow may not be checked even if $stackck is on.

 The use of INTERRUPT procedures introduces re-entrancy into MS-Pascal
 code: generated code is re-entrant, as is the runtime system (except for
 the heap unit and, in most operating systems, portions of the file unit).

 Some critical sections in the runtime system are protected by
 semaphores that generate a runtime error if such a critical section is
 locked.  For example, if the heap allocator is executing when an interrupt
 occurs and the INTERRUPT procedure tries to allocate a block from the heap,
 the structure of the heap could become invalid. This condition causes a
 runtime error.

 However, in most cases, the file system is not protected by a
 semaphore. Therefore, it is safest to avoid performing any I/O within the
 INTERRUPT procedure. Alternatively, you can avoid most problems with I/O in
 an INTERRUPT procedure by not opening or closing any files (i.e., not
 declaring any local file variables or creating files on the heap) and by
 not performing input or output with any file that might be in the process
 of performing I/O when the interrupt occurs.


 14.3.7  The PURE Attribute


 The PURE attribute applies only to functions, not to procedures or
 variables. PURE indicates to the compiler's optimizer that the function
 does not modify any global variables either directly or by calling some
 other procedure or function.

 Example of a PURE declaration:

      FUNCTION AVERAGE (CONST TABLE : RVECTOR):
      REAL [PURE];

 For further illustration, examine these statements:

      A := VEC [I * 10 + 7];
      B := FOO;
      C := VEC [I * 10 + 9];

 If the function FOO is given the PURE attribute, the optimizer only
 generates code to compute I * 10 once. However, FOO, if it is not declared
 PURE, may modify I so that I * 10 must be recomputed after the call to FOO.

 Functions are not considered PURE unless given the attribute explicitly
 The compiler checks to see that a PURE function does not do any of the
 following:

     1.  assign to a nonlocal variable

     2.  have any VAR or VARS parameters (CONST and CONSTS parameters are
         permitted)

     3.  call any functions that are not PURE

 Although the following additional restrictions are not checked, a PURE
 function should also:

     1.  not use the value of a global variable

     2.  not modify the referents of references passed by a value (e.g.,
         pointer or address type referents)

     3.  not do input or output

 Since the result of a PURE function with the same parameters must
 always be the same, the entire function call may be optimized away.  For
 example, if in the following statements DSIN is PURE; the compiler only
 calls DSIN once:

      HX := A * DSIN (P[I, J] * 2);
      HY := B * DSIN (P[I, J] * 2);


 14.4  Procedure and Function Parameters


 Procedures and functions may take three different types of parameters:

     1.  value parameters

     2.  reference parameters

     3.  procedural and functional parameters

 Each of these is discussed separately, in the order listed, in the
 following sections.

 The discussion mentions both formal and actual parameters. A formal
 parameter is the parameter given when the procedure or function is
 declared, with an identifier in the heading. When the function or
 procedure is called, an actual parameter substitutes for the formal
 parameter given earlier; here the parameter takes the form of a variable or
 value or expression.

 MS-Pascal has several parameter features at the extend level:

     1.  A super array type can be passed as a reference parameter.

     2.  A reference parameter can be declared READONLY.

     3.  Explicit segmented reference parameters can be declared.


 14.4.1  Value Parameters


 When a value parameter is passed, the actual parameter is an
 expression. That expression is evaluated in the scope of the calling
 procedure or function and assigned to the formal parameter. The formal
 parameter is a variable local to the procedure or function called.  Thus,
 formal value parameters are always local to a procedure or function.

 Example of value parameters:

     {Function declaration}
     FUNCTION ADD (A, B, C : REAL) : REAL;
        {A, B, and C are formal parameters}
       .
       .
     X := ADD (Y, ADD (1.111, 2.222, 3.333), (Z * 4))

 In this particular function invocation, Y, ADD(...), and (Z * 4) are
 the expressions that make up the actual parameters.  In this example, these
 expressions must all evaluate to the type REAL. (The example also
 recursively calls the function ADD.)

 The actual parameter expression must be assignment compatible with
 the type of the formal parameter.

 Passing structured types by value is permitted; however, it is
 inefficient, since the entire structure must be copied. A value parameter
 of a SET, LSTRING, or subrange type may also require a runtime error check
 if the range checking switch is on. In addition, SET and LSTRING value
 parameters may require extra generated code for size adjustment.

 A file variable or super array variable cannot be passed as a value
 parameter, since it cannot be assigned. However, a variable with a type
 derived from a super array or file buffer variable can be passed. Passing a
 file buffer variable as a value parameter implies normal evaluation of the
 buffer variable.


 14.4.2  Reference Parameters


 When a reference parameter is passed at the standard level of MS-
 Pascal, the keyword VAR precedes the formal parameter. Furthermore, the
 actual parameter must be a variable, not an expression.  The formal
 parameter denotes this actual variable during the execution of the
 procedure. Any operation on the formal parameter is performed immediately
 on the actual parameter, by passing the machine address of the actual
 variable to the procedure. For target processors with segmentation support,
 this address is an offset into the default data segment.

 Example of variable parameters:

     PROCEDURE CHANGE_VARS (VAR A, B, C : INTEGER);
     {A, B, and C are formal reference parameters.}
     {They denote variables, not values.}
       .
       .
     CHANGE_VARS (X, Y, Z);

 In this example, X, Y, and Z must be variables, not expressions.
 Also, the variables X, Y, and Z are altered whenever the formal parameters
 A, B, and C are altered in the declared procedure. This differs from the
 handling of value parameters, which can affect only the copies of values of
 variables.  If the selection of the variable involves indexing an array or
 dereferencing a pointer or address, these actions are executed before the
 procedure itself. The type of the actual parameter must be identical to the
 type of the formal parameter.

 Passing a nonlocal variable as a VAR parameter puts a slash (/) or
 percent sign (%) in the G (global) column of the listing file (see Section
 18.5, "Listing File Format," for information about the significance of
 these characters in the G column of the listing).

 None of the following may be passed as VAR parameters:

     1.  a component of a PACKED structure (except CHAR of a STRING or
         LSTRING)

     2.  any variable with a READONLY or PORT attribute (includes CONST and
         CONSTS parameters and the FOR control variable)

 Passing a file buffer variable by reference generates a warning
 message, because it bypasses the normal file system call generated by the
 use of any buffer variable. These calls are not generated when a file
 variable is passed by reference.

 On a segmented machine, a VAR parameter passes an address that is
 really an offset into a default data segment. In some cases, access to
 objects residing in other segments is required. To pass these objects by
 reference, you must tell the compiler to use a segmented address containing
 both segment register and offset values. The extend level includes the
 parameter prefix VARS instead of VAR:

      PROCEDURE CONCATS (VARS T, S : STRING);

 You may only use VARS as a data parameter in procedures and functions,
 not in the declaration section of programs, procedures, and functions.
 VARS and CONSTS parameters are provided chiefly to maintain compatibility
 with machines that have two different size address spaces. These
 parameters are not necessary for a machine with a single size address
 space. On such machines, the reserved words VARS and CONSTS are equivalent
 to VAR and CONST.


 14.4.2.1  Super Array Parameters

 Super array parameters may appear as formal reference parameters.  This
 allows a procedure or function to operate on an array with a particular
 super array type (also a component type and index type), but without any
 fixed upper bounds.  The formal parameter is a reference parameter of the
 super array type itself.

 The actual parameter type must be a type derived from the super array
 type or the super array type itself (i.e., another reference parameter or
 dereferenced pointer). Except for comparing LSTRINGs, super array type
 parameters cannot be assigned or compared as a whole.

 The actual upper and lower bounds of the array are available with the
 UPPER and LOWER functions; this permits routines that can operate on arrays
 of any size. An LSTRING actual parameter can be passed to a reference
 parameter of the super array type STRING. Therefore, the super array
 parameter STRING can be used for procedures and functions that operate on
 strings of both STRING and LSTRING types.

 Example of super array parameters:

      TYPE REALS = ARRAY [0..*] OF REAL;

      PROCEDURE SUMRS (VAR X : REALS; CONST X : REALS);
      BEGIN
        .
        .
      END;

 For more information, see the following sections of this manual:

 Section 7.2, "Super Arrays"

 Section 7.2.1, "STRINGs"

 Section 7.2.2, "LSTRINGs"


 14.4.2.2  Constant and Segment Parameters

 At the extend level, a formal parameter preceded by the reserved word
 CONST implies that the actual parameter is a READONLY reference parameter.
 This is especially useful for parameters of structured types, which may be
 constants, since it eliminates the need for a time-consuming value
 parameter copy.  The actual parameter can be a variable, function result,
 or constant value.

 No assignments can be made to the CONST parameter or any of its
 components. CONST super array types are permitted.  A CONST parameter in
 one procedure cannot be passed as a VAR parameter to another procedure.
 However, it is permissible to pass a VAR parameter in one procedure as a
 CONST parameter in another.

 Example of a CONST parameter:

      PROCEDURE ERROR (CONST ERRMSG : STRING);

 On a segmented machine, a CONST parameter passes an address that is really
 an offset into a default data segment. In some cases, access to objects
 residing in other segments is required. To pass these objects by reference,
 you must tell the compiler to use a segmented address that contains both
 segment register and offset values. The extend level includes the
 parameter prefix CONSTS, instead of CONST. Use of CONSTS parameters
 parallels use of VARS for formal reference parameters.

 Example of a CONSTS parameter:

      PROCEDURE CAT (VARS T : STRING; CONSTS S : STRING);

 A CONSTS parameter can only be used as a data parameter in procedures and
 functions, not in the declaration section of programs, procedures, and
 functions.

 You can also pass the value of an expression as a CONST or CONSTS
 parameter. The expression is evaluated and assigned to a temporary (hidden)
 variable in the frame of the calling procedure or function. You should
 enclose such an expression in parentheses to force its evaluation.

 A function identifier can be passed by reference as a VAR, VARS,
 CONST, or CONSTS parameter. The function's local variable is passed, so the
 call must occur in the function's body or in a procedure or function
 declared with the function.

 The value returned by a function designator can also be passed, like
 any expression, as a CONST or CONSTS parameter. Like any expression passed
 by reference, the function designator should be enclosed in parentheses, as
 shown:

      PROCEDURE WRITE_ANSWER (CONSTS A : INTEGER);
      BEGIN
         WRITELN ('THE ANSWER IS ,' A)
      END;

      FUNCTION ANSWER : INTEGER;
      BEGIN
         ANSWER := 42;
         WRITE_ANSWER (ANSWER);
         {Pass reference to local variable.}
      END;

      PROCEDURE HITCH_HIKE;
      BEGIN
         WRITE_ANSWER ((ANSWER))
         {Call ANSWER, assign to temporary variable,}
         {pass reference to temporary variable.}
      END;


 14.4.3  Procedural and Functional Parameters


 Procedural parameters can be used in the following circumstances:

     1.  in numerical analysis

     2.  in calling some library routines

     3.  in special applications

 In numerical analysis, you might pass a function to a procedure or
 function that finds an integral between limits, a maximum or minimum value,
 and so on. Some interesting algorithms in areas such as parsing and
 artificial intelligence also use procedural parameters.

 When a procedural or functional parameter is passed, the actual
 identifier is that for a procedure or function. The formal parameter is
 a procedure or function heading, including any attributes, preceded by the
 reserved word PROCEDURE or FUNCTION.

 For example, examine these declarations:


       TYPE DOOR  = (FRONT, BARN, CELL, DOG_HOUSE);
           SPEED  = (FAST, SLOW, NORMAL);
           DIRECTION = (OPEN, SHUT);

      PROCEDURE OPEN_DOOR_WIDE
         (VAR A : DOOR;  B : SPEED; C : DIRECTION);
          .
          .
      PROCEDURE SLAM_DOOR
         (VAR DR : DOOR; SP : SPEED; DIR : DIRECTION);
          .
          .
      PROCEDURE LEAVE_AJAR
         (VAR DD : DOOR; SS : SPEED; DD : DIRECTION);

 All of the procedures in the example have parameter lists of equal
 length. The types of the parameters are not only compatible, but also
 identical.  The formal parameters need not be identically named.

 A procedural or functional parameter can accept one of these
 procedures if the procedure or function is set up correctly, as shown:


     FUNCTION DOOR_STATUS (PROCEDURE MOVE_DOOR)
        (VAR X : DOOR; Y :SPEED; Z : DIRECTION);
        (VAR XX : DOOR; YY : SPEED; ZZ : DIRECTION) : INTEGER;
        {"PROCEDURE MOVE_DOOR" is the formal procedural}
        {parameter; the next two lines are other formal}
        {parameters.}

     BEGIN {door_status}
        DOOR_STATUS := 0;
        MOVE_DOOR (XX, YY, ZZ);
        {One of the three procedures declared}
        {previously is executed here.}

        IF  XX = BARN AND ZZ = SHUT
        THEN DOOR_STATUS := 1;

        IF  XX = CELL AND ZZ = OPEN
        THEN DOOR_STATUS := 2;

        IF  XX = DOG_HOUSE AND ZZ = SHUT
        THEN DOOR_STATUS := 3
     END;

 Use of the procedural parameter MOVE_DOOR might occur in program statements
 as follows:

      IF DOOR_STATUS
         (SLAM_DOOR, CELL, FAST, SHUT) = 0
      THEN
         SOCIETY := SAFE;
      IF DOOR_STATUS
         (OPEN_DOOR_WIDE, BARN, SLOW, OPEN) = 0
      THEN
         COWS_ARE_OUT := TRUE;
      IF DOOR_STATUS
         (LEAVE_AJAR, DOG_HOUSE, SLOW, OPEN) = 0
      THEN
         DOG_CAN_GET_IN := TRUE;

 In each case above, the actual procedure list is compatible with the formal
 list, both in number and in type of parameters.  If the parameter passed
 were a functional parameter, then the function return value would also have
 to be of an identical type.

 In addition, the set of attributes for both the formal and actual
 procedural type must be the same, except that the PUBLIC and ORIGIN
 attributes and EXTERN directive are ignored.

 A PUBLIC or EXTERN procedure, or any local procedure at any nesting
 level, can be passed to the same type of formal parameter. However, the
 PURE attribute and any calling sequence attributes must match. Also, in
 systems with segmented code addresses, a procedure or function passed as a
 parameter to an EXTERN procedure or function must itself be PUBLIC or
 EXTERN.

 In MS-Pascal, you cannot pass predeclared procedures and functions
 compiled as inline code; you can only pass them in called subroutines.
 Also, the READ, WRITE, ENCODE, and DECODE families are translated into
 other calls by the compiler, based on the argument types, and so cannot be
 passed. Corresponding routines in the file unit or encode/decode unit can
 be passed, however. For example, a READ of an INTEGER becomes a call to
 RTIFQQ and this procedure can be passed as a parameter.


 The following intrinsic procedures and functions cannot be passed as
 procedure or function parameters:


     1.  at the standard level of MS-Pascal:

         ABS           EOLN         PACK        SQR
         ARCTAN        EXP          PAGE        SQRT
         CHR           LN           PRED        SUCC
         COS           NEW          READ        UNPACK
         DISPOSE       ODD          READLN      WRITE
         EOF           ORD          SIN         WRITELN

     2.  at the extend and system levels of MS-Pascal:

         BYLONG        FLOAT4       READFN      SIZEOF
         BYWORD        HIBYTE       READSET     TRUNC
         DECODE        HIWORD       RESULT      TRUNC4
         ENCODE        LOBYTE       RETYPE      UPPER
         EVAL          LOWER        ROUND       WRD
         FLOAT         LOWORD       ROUND4

 When a procedure or function passed as a parameter is finally activated,
 any nonlocal variables accessed are those in effect at the time the
 procedure or function is passed as a parameter, rather than those in effect
 when it is activated. Internally, both the address of the routine and the
 address of the upper frame (in the stack) are passed.

 Example of formal procedure use:

      PROCEDURE ALPHA;
        VAR I : INTEGER;

        PROCEDURE DELTA;
          BEGIN
            WRITELN ('Delta done')
          END;

        PROCEDURE BETA (PROCEDURE XPR);
          VAR GLOB : INTEGER;

          PROCEDURE GAMMA;
            BEGIN GLOB := GLOB + 1 END;
          BEGIN  {Start BETA}
            GLOB := 0;
            IF I = 0
              THEN BEGIN
                 I := 1;  XPR; BETA (GAMMA)
                 END
              ELSE BEGIN
                 GLOB := GLOB + 1; XPR
                 END
          END;

        BEGIN  {Start ALPHA}
          I := 0;
          BETA (DELTA)
        END;

 The following list describes what happens in this example:

     1.  ALPHA is called.

     2.  BETA is called, passing the procedure DELTA.

     3.  This latter call creates an instance of GLOB on the stack (call it
         GLOB1).

     4.  BETA first clears GLOB1 by setting it to zero. Then, since I is 0,
         the THEN clause is executed, which sets I to one and executes XPR,
         which is bound to DELTA.

     5.  Therefore, 'Delta done' is written to OUTPUT.

     6.  Now BETA is called recursively. BETA is passed the address of
         GAMMA, and, at this time, the access path to any nonlocal variables
         used by GAMMA (i.e., GLOB1) is passed as well.

     7.  The second call to BETA creates another instance of GLOB (GLOB2).
         When GLOB2 is cleared this time, I is 1, so GLOB2 is incremented.

     8.  Then XPR is called, which is bound to GAMMA, so GAMMA is executed
         and increments the instance of GLOB active when GAMMA was passed to
         BETA, GLOB1.

     9.  GAMMA returns, the second BETA call returns, the first BETA call
         returns, and finally, ALPHA returns.



 Chapter 15  Available Procedures and Functions

 

 15.1  Categories of Available Procedures and Functions

        15.1.1  File System Procedures and Functions

        15.1.2  Dynamic Allocation Procedures

        15.1.3  Data Conversion Procedures and Functions

        15.1.4  Arithmetic Functions

        15.1.5  Extend Level Intrinsics

        15.1.6  System Level Intrinsics

        15.1.7  String Intrinsics

        15.1.8  Library Procedures and Functions

 15.2  Directory of Functions and Procedures



 All versions of Pascal predeclare a large number of common procedures
 and functions.  You do not have to declare these procedures and functions
 in a program. Since they are defined in a scope "outside" the program, you
 may redefine these identifiers

 To promote portability, Microsoft Pascal makes some of the predeclared
 procedures and functions available only at the extend or at the system
 level. MS-Pascal also includes some useful library procedures and functions
 that you must declare EXTERN in order to use.

 MS-Pascal implements three kinds of procedures and functions:

     1.  Some are predeclared, and the compiler translates them into other
         calls or special generated code (these you cannot pass as
         parameters).

     2.  Some are predeclared but you call them normally (except for a name
         change).

     3.  Some are not predeclared but are available as part of the MS-Pascal
         runtime library (these you must declare explicitly).

 However, it is more useful when discussing these procedures and functions
 to categorize them by what they do rather than by how they are implemented.
 Table 15.1 shows this categorization.


 Table 15.1
 Categories of Available Procedures and Functions
ķ
 Category                 Purpose
 
 File system              Operate on files of different
                          modes and structures

 Dynamic                  Dynamically allocate and
 allocation               deallocate data structures on
                          the heap at runtime

 Data                     Convert data from one type to
 conversion               another

 Arithmetic               Perform common transcendental
                          and other numeric functions

 Extend level             Provide additional procedures
 intrinsics               and functions at the extend
 Category                 Purpose
intrinsics               and functions at the extend
                          level of MS-Pascal

 System level             Provide additional procedures
 intrinsics               and functions at the system
                          level of MS-Pascal

 String                   Operate on STRING and LSTRING
 intrinsics               type data

 Library                  Available in the MS-Pascal
                          runtime library:  they are not
                          predeclared; you must declare
                          them with the EXTERN directive


 15.1  Categories of Available Procedures and Functions


 The rest of this chapter is divided into two sections. Section 15.1
 describes each of the categories shown in the preceding table and lists the
 procedures and functions each category includes. Section 15.2 is an
 alphabetical directory of all of the available procedures and functions.
 Each entry includes the syntax and a description, plus examples and notes
 as appropriate.


 15.1.1  File System Procedures and Functions


 The MS-Pascal file system supports a variety of procedures and functions
 that operate on files of different modes and structures. These procedures
 and functions fall into three categories, as shown in Table 15.2.


 Table 15.2
 File System Procedures and Functions
ķ
 Category                Procedures         Functions
 
 Primitive               GET                EOF
 Category                Procedures         Functions
Primitive               GET                EOF
                         PAGE               EOLN
                         PUT
                         RESET
                         REWRITE


 Textfile I/O            READ
                         READLN
                         WRITE
                         WRITELN


 Extend Level I/O        ASSIGN
                         CLOSE
                         DISCARD
                         READSET
                         READFN
                         SEEK

 For details on each of these procedures and functions, see Chapter 16,
 "File-Oriented Procedures and Functions."


 15.1.2  Dynamic Allocation Procedures


 Two procedures, NEW and DISPOSE, allow dynamic allocation and deallocation
 of data structures at runtime. NEW allocates a variable in the heap, and
 DISPOSE releases it.


 15.1.3  Data Conversion Procedures and Functions


 Use the following procedures and functions to convert data from one type to
 another:

     CHR              PACK             TRUNC
     FLOAT            PRED             TRUNC4
     FLOAT4           ROUND            UNPACK
     ODD              ROUND4           WRD
     ORD              SUCC

 Four of these convert any ordinal type to a particular ordinal type:

     1.  CHR (ordinal) to CHAR

     2.  ODD (ordinal) to BOOLEAN

     3.  ORD (ordinal) to INTEGER

     4.  WRD (ordinal) to WORD

 PRED and SUCC also operate on ordinal types.

 Six of the conversion procedures and functions convert between INTEGER
 or INTEGER4 and REAL:

     1.  FLOAT    converts   INTEGER    to   REAL

     2.  FLOAT4   converts   INTEGER4   to   REAL

     3.  ROUND    converts   REAL       to   INTEGER

     4.  ROUND4   converts   REAL       to   INTEGER4

     5.  TRUNC    converts   REAL       to   INTEGER

     6.  TRUNC4   converts   REAL       to   INTEGER4

 PACK and UNPACK transfer components between packed and unpacked
 arrays.


 15.1.4  Arithmetic Functions


 All arithmetic functions take a CONSTS parameter of type REAL4 or
 REAL8, or a type compatible with INTEGER (labeled "numeric" in the
 directory). ABS and SQR also take WORD and INTEGER4 values.

 All functions on REAL data types check for an invalid (uninitialized)
 value. They also check for particular error conditions and generate a
 runtime error message if an error condition is found.

 If the math checking switch is on, errors in the use of the functions
 ABS and SQR on INTEGER, WORD, and INTEGER4 data generate a runtime error
 message. If the switch is off, the result of an error is undefined.

 Table 15.3 lists the arithmetic functions available, along with the
 routines called depending on whether single or double precision is
 required.


 Table 15.3
 Predeclared Arithmetic Functions
ķ
 Name       Operation          REAL4          REAL8
 
 ABS        Absolute value     (inline)       (inline)
 ARCTAN     Arc tangent        ATSRQQ         ATDRQQ
 COS        Cosine             CNSRQQ         CNDRQQ
 EXP        Exponential        EXSRQQ         EXDRQQ
 Name       Operation          REAL4          REAL8
EXP        Exponential        EXSRQQ         EXDRQQ
 LN         Natural log        LNSRQQ         LNDRQQ
 SIN        Sine               SNSRQQ         SNDRQQ
 SQR        Square             (inline)       (inline)
 SQRT       Square root        SRSRQQ         SRDRQQ

 The MS-FORTRAN runtime library provides several additional REAL4 and REAL8
 functions, as shown in Table 15.4. If you use them, you must declare them
 with the EXTERN directive.


 Table 15.4
 REAL Functions from the Microsoft FORTRAN Runtime Library
ķ
 Operation                   REAL4             REAL8
 
 Arc cosine                  ACSRQQ            ACDRQQ
 Integral trunc              AISRQQ            AIDRQQ
 Integral round              ANSRQQ            ANDRQQ
 Arc sine                    ASSRQQ            ASDRQQ
 Operation                   REAL4             REAL8
Arc sine                    ASSRQQ            ASDRQQ
 Arc tangent A/B             A2SRQQ            A2DRQQ
 Hyperbolic cosine           CHSRQQ            CHDRQQ
 Decimal log                 LDSRQQ            LDDRQQ
 Modulo                      MDSRQQ            MDDRQQ
 Minimum                     MNSRQQ            MNDRQQ
 Maximum                     MXSRQQ            MXDRQQ
 Power (REAL8**INTG4)                          PIDRQQ
 Power (REAL4**INTG4)        PISRQQ
 Power (REAL ** REAL)        PRSRQQ            PRDRQQ
 Hyperbolic sine             SHSRQQ            SHDRQQ
 Hyperbolic tangent          THSRQQ            THDRQQ
 Tangent                     TNSRQQ            TNDRQQ

 Some common mathematical functions are not standard in Pascal, but are
 relatively simple to accomplish with program statements or to define as
 functions in a program. Some typical definitions follow:

     SIGN (X) is ORD (X > 0) - ORD (X < 0)
     POWER (X, Y) is EXP (Y * LN (X))

 You could also write your own functions in MS-Pascal to do the same thing.
 Defining functions like these is a good opportunity to use the PURE
 attribute (to obtain more efficient code). For example:

     FUNCTION POWER (A, B : REAL) : REAL [PURE];
     BEGIN
       IF A <= 0 THEN
          ABORT ('Nonplus real to power', 24, 0);
          POWER := EXP (B * LN (A))
     END;


 15.1.5  Extend Level Intrinsics


 At the extend level of MS-Pascal, the following intrinsic procedures
 and functions are available:

     ABORT             EVAL             LOWORD
     BYLONG            HIBYTE           RESULT
     BYWORD            HIWORD           SIZEOF
     DECODE            LOBYTE           UPPER
     ENCODE            LOWER

 Several of these are used to compose and decompose one-byte, two-byte,
 and four-byte items: HIBYTE, LOBYTE, BYWORD, HIWORD, LOWORD, and BYLONG.

 ENCODE and DECODE convert between internal and string forms of
 variables. ABORT invokes a runtime error.

 The others, EVAL, LOWER, UPPER, RESULT, and SIZEOF, are used in
 special situations (described for each function in Section 15.2,
 "Directory of Functions and Procedures").


 15.1.6  System Level Intrinsics


 Several additional intrinsic procedures and functions are available at
 the system level:

     FILLC               MOVESL
     FILLSC              MOVESR
     MOVEL               RETYPE
     MOVER

 The MOVE and FILL procedures perform low-level operations on byte
 strings. RETYPE changes the type of an expression arbitrarily.


 15.1.7  String Intrinsics


 The string intrinsics feature provides a set of procedures and
 functions, some of which operate on STRINGs and LSTRINGs, and some on
 LSTRINGs only as shown in Table 15.5:

        Table 15.5
        String Procedures and Functions
ķ
        Name               Parameter
        
        Name               Parameter
        
        CONCAT             STRING
        DELETE             STRING
        INSERT             STRING
        COPYLST            STRING

        COPYSTR            STRING or LSTRING
        POSITN             STRING or LSTRING
        SCANEQ             STRING or LSTRING
        SCANNE             STRING or LSTRING


 15.1.8  Library Procedures and Functions


 The following routines are not predeclared, but are available to you in
 the MS-Pascal runtime library. You must declare them, with the EXTERN
 directive, before using them in a program.

     1.  Initialization and termination routines

         BEGOQQ and ENDOQQ are called during initialization and termination,
         respectively.  You might use them to invoke a debugger or to write
         customized messages, such as the time of execution, to the terminal
         screen.  BEGXQQ may be called to restart a program and ENDXQQ to
         terminate it.

     2.  Heap management routines

         Heap management routines complement the standard NEW and DISPOSE
         procedures and include:

         ALLHQQ
         FREECT
         MARKAS
         MEMAVL
         RELEAS

     3.  Interrupt routines

         These routines handle interrupt processing, although the actual
         effect varies with the target machine:

         ENABIN
         DISABIN
         VECTIN

     4.  Terminal I/O routines

         The following routines support direct input to and output from
         your terminal:

         GTYUQQ
         PTYUQQ
         PLYUQQ

     5.  Semaphore routines

         The two procedures, LOCKED and UNLOCK, provide a binary semaphore
         capability. You can use them to ensure exclusive access of a
         resource in a concurrent system.

     6.  No-overflow arithmetic functions

         These functions implement 16-bit and 32-bit modulo arithmetic.
         Overflow or carry is returned, instead of invoking a runtime error.

         LADDOK
         LMULOK
         SADDOK
         SMULOK
         UADDOK
         UMULOK

     7.  Clock routines

         These provide operating system clock information:

         TIME
         DATE
         TICS


 15.2  Directory of Functions and Procedures


 This section contains a list of all available procedures and functions,
 both those that are predeclared and those library routines that may be used
 if declared EXTERN. Each entry includes the heading, the category to which
 the operation belongs, and a description of what the procedure or function
 does. Notes and examples are included as appropriate. The headings given
 are the same for both REAL4 or REAL8, unless specifically stated otherwise.


 PROCEDURE ABORT (CONST STRING, WORD, WORD);

       An extend level intrinsic procedure. Halts program execution in the
       same way as an internal runtime error. The STRING (or LSTRING) is an
       error message. The string parameter is a CONST, not a CONSTS
       parameter. The first WORD is an error code; the second WORD can be
       anything. The second WORD is sometimes used to return a file error
       status code from the operating system.

       The parameters, as well as any information about the machine
       state (program counter, frame pointer, stack pointer) and the source
       position of the ABORT call (if the $line and/or $entry debugging
       switches are on), are given to you in a termination message or are
       available to the debugging package.

       If the $runtime switch is on, then error messages report the
       location of the procedure or function that has called the routine in
       which abort was called. If $runtime is on, $line and $entry should
       be off, and routines in a source file should only call other $runtime
       routines.


 FUNCTION ABS (X : NUMERIC) : NUMERIC;

       An arithmetic function. Returns the absolute value of X. Both X and
       the return value are of the same numeric type: REAL4, REAL8, INTEGER,
       WORD, or INTEGER4. Since WORD values are unsigned, ABS (X) always
       returns X if X is of type WORD.


 FUNCTION ACSRQQ (CONSTS A : REAL4) : REAL4;
 FUNCTION ACDRQQ (CONSTS A : REAL8) : REAL8;

       Arithmetic functions. Return the arc cosine of A. Both A and the
       return value are of type REAL4 or REAL8, as shown. These functions
       are from the MS-FORTRAN runtime library and must be declared EXTERN
       before use.


 FUNCTION AISRQQ (CONSTS A : REAL4) : REAL4;
 FUNCTION AIDRQQ (CONSTS A : REAL8) : REAL8;

       Arithmetic functions. Return the integral part of A, truncated toward
       zero. Both A and the return value are of type REAL4 or REAL8, as
       shown.  These functions are from the MS-FORTRAN runtime library and
       must be declared EXTERN before use.


 FUNCTION ALLHQQ (SIZE : WORD) : WORD;

       A library routine (heap management function).  Returns zero if
       the heap is full, one if the heap structure is in error, or MAXWORD
       if the allocator has been interrupted.  Otherwise, it returns the
       pointer value for an allocated variable with the size requested.

       Generally, you use ALLHQQ with the RETYPE function.  For
       example:

           P_VAR := RETYPE (P_TYPE, ALLHQQ (28));
           {RETYPE converts the value returned by}
           {ALLHQQ (28) to the type P_TYPE.}
           {This value is assigned to P_VAR.}

           IF WRD (P_VAR) < 2 THEN GO_ABORT;
           is then checked for a heap}
           {full or heap structure error.}


 FUNCTION ALLMQQ (WANTS : WORD) : ADSMEM;

       A library routine (segmented heap management function). This
       function returns a long segmented address of type ADSMEM. ALLMQQ
       takes a parameter "wants" that is a memory request in bytes.

       A number "0" in the ".r" field of the segmented address returned by
       ALLMQQ indicates that memory of the requested "wants" size could not
       be allocated. A number "1" indicates that the long segmented heap is
       invalid.

       ALLMQQ may not be available in your implementation of MS-Pascal;
       see the "Version Specifics" Appendix of your Microsoft Pascal
       Compiler User's Guide.


 FUNCTION ANSRQQ (CONSTS A : REAL4) : REAL4;
 FUNCTION ANDRQQ (CONSTS A : REAL8) : REAL8;

       Arithmetic functions. Like AISRQQ and AIDRQQ, return the truncated
       integral part of A, but round away from zero. Both A and the return
       value are of type REAL4 or REAL8, as shown. These functions are from
       the MS-FORTRAN runtime library and must be declared EXTERN before
       use.


 FUNCTION ARCTAN (X : REAL) : REAL;

       An arithmetic function. Returns the arc tangent of X in radians.
       Both X and the return value are of type REAL. To force a particular
       precision, declare ATSRQQ (CONSTS REAL4) and/or ATDRQQ (CONSTS REAL8)
       and use them instead.


 FUNCTION ASSRQQ (CONSTS A : REAL4) : REAL4;
 FUNCTION ASDRQQ (CONSTS A : REAL8) : REAL8;

       Arithmetic functions. Return the arc sine of A. Both A and the
       return value are of type REAL4 or REAL8, as shown. These functions
       are from the MS-FORTRAN runtime library and must be declared EXTERN
       before use.


 PROCEDURE ASSIGN (VAR F; CONSTS N : STRING);

       A file system procedure (extend level I/O). Assigns an operating
       system filename in a STRING (or LSTRING) to a file F.

       See Section 16.3.1, "Extend Level Procedures," for a description
       of ASSIGN.


 FUNCTION ATSRQQ (CONSTS A : REAL4) : REAL4;
 FUNCTION ATDRQQ (CONSTS A : REAL8) : REAL8;

       See FUNCTION ARCTAN


 FUNCTION A2SRQQ (A, B : REAL4) : REAL4;
 FUNCTION A2DRQQ (A, B : REAL8) : REAL8;

       Arithmetic functions. Return the arc tangent of (A/B). Both A and B,
       as well as the return value, are of type REAL4 or REAL8, as shown.
       These functions are from the MS-FORTRAN runtime library and must be
       declared EXTERN before use.


 PROCEDURE BEGOQQ;

       A library routine (initialization). BEGOQQ is called during
       initialization, and the default version does nothing. However, you
       may write your own version of BEGOQQ, if you want, to invoke a
       debugger or to write customized messages, such as the time of
       execution, to a terminal screen.

       See also PROCEDURE ENDOQQ.


 PROCEDURE BEGXQQ;

       A library routine (initialization). After your program is linked
       and loaded, BEGXQQ is the defined entry point for the load module.

       As the overall initialization routine, BEGXQQ performs the
       following actions:

       1.  It resets the stack and the heap.

       2.  It initializes the file system.

       3.  It calls BEGOQQ.

       4.  It calls the program body.

       BEGXQQ may be useful for restarting after a catastrophic error in
       a ROM-based system. However, invoking this procedure to restart a
       program does not take care of closing any files that may have
       previously been opened. Similarly, it does not re-initialize
       variables originally set in a VALUE section or with the
       initialization switch on.


 FUNCTION BYLONG (INTEGER-WORD, INTEGER-WORD) : INTEGER4;

       An extend level intrinsic function. Converts WORDs or INTEGERs (or
       the LOWORDs of INTEGER4s) to an INTEGER4 value. BYLONG concatenates
       its operands:

       BYLONG (A,B) =
       ORD (LOWORD (A)) * 65535 + WRD (HIWORD (B))

       If the first value is of type WORD, its most significant bit
       becomes the sign of the result.


 FUNCTION BYWORD (ONE-BYTE, ONE-BYTE) : WORD;

       An extend level intrinsic function. Converts bytes (or the
       LOBYTEs of INTEGERs or WORDs) to a WORD value. Takes two parameters
       of any ordinal type. BYWORD returns a WORD with the first byte in
       the most significant part and the second byte in the least
       significant part:

          BYWORD (A,B) = LOBYTE(A) * 256 + LOBYTE(B)

       If the first value is of type WORD, its most significant bit
       becomes the sign of the result.


 FUNCTION CHR (X : ORDINAL) : CHAR;

       A data conversion function. Converts any ordinal type to CHAR. The
       ASCII code for the result is ORD (X). This is an extension to the
       ISO standard, which requires X to be of type INTEGER. An error
       occurs if ORD (X) > 255 or ORD (X) < 0. However, the error is caught
       only if the range checking switch is on.


 FUNCTION CHSRQQ (CONSTS A : REAL4) : REAL4;
 FUNCTION CHDRQQ (CONSTS A : REAL8) : REAL8;

       Arithmetic functions. Return the hyperbolic cosine of A. Both A and
       the return value are of type REAL4 or REAL8, as shown. These
       functions are from the MS-FORTRAN runtime library and must be
       declared EXTERN before use.


 PROCEDURE CLOSE (VAR F);

       A file system procedure (extend level I/O). Performs an operating
       system close on a file, ensuring that the file access is terminated
       correctly.

       See Section 16.3.1, "Extend Level Procedures," for a description
       of CLOSE.

 FUNCTION CNSRQQ (CONSTS A : REAL4) : REAL4;
 FUNCTION CNDRQQ (CONSTS A : REAL4) : REAL4;

       See FUNCTION COS.


 PROCEDURE CONCAT (VARS D : LSTRING; CONSTS S : STRING);

       A string intrinsic procedure. Concatenates S to the end of D.
       The length of D increases by the length of S. An error occurs if D
       is too small, i.e., if UPPER (D) < D.LEN + UPPER (S).


 PROCEDURE COPYLST (CONSTS S : STRING; VARS D : LSTRING);

       A string intrinsic procedure. Copies S to LSTRING D. The length of D
       is set to UPPER (S). An error occurs if the length of S is greater
       than the maximum length of D, i.e., if UPPER (S) > UPPER (D).


 PROCEDURE COPYSTR (CONSTS S : STRING; VARS D : STRING);

       A string intrinsic procedure. Copies S to STRING D. The remainder of
       D is set to blanks if UPPER (S) < UPPER (D). An error occurs if the
       length of S is greater than the maximum length of D, i.e., if
       UPPER (S) > UPPER (D).


 FUNCTION COS (X : NUMERIC) : REAL;

       An arithmetic function. Returns the cosine of X in radians. Both X
       and the return value are of type REAL. To force a particular
       precision, declare CNSRQQ (CONSTS REAL4) and/or CNDRQQ (CONSTS REAL8)
       and use them instead.


 PROCEDURE DATE (VAR S : STRING);

       A clock procedure. If available, this procedure assigns the current
       date to its STRING (or LSTRING) variable. If an LSTRING is passed as
       the parameter, you must set the length you want before calling the
       procedure. The format depends on the target operating system.


 FUNCTION DECODE (CONST LSTR : LSTRING, X : M : N) : BOOLEAN;

       An extend level intrinsic function. Converts the character string in
       the LSTRING to its internal representation and assigns this to X. If
       the character string is not a valid external ASCII representation of
       a value whose type is assignment compatible with X, DECODE returns
       FALSE and the value of X is undefined.

       DECODE works exactly the same as the READ procedure, including
       the use of M and N parameters (see Section 16.2.2, "READ Formats,"
       for a discussion of these parameters). When X is a subrange, DECODE
       returns FALSE if the value is out of range (regardless of the setting
       of the range checking switch.) Leading and trailing spaces and tabs
       in the LSTRING are ignored. All other characters in the LSTRING must
       be part of the representation.

       X must be one of the types INTEGER, WORD, enumerated, one of
       their subranges, BOOLEAN, REAL4, REAL8, INTEGER4, or a pointer
       (address types need the .R or .S suffix).

       In a segmented memory environment, the LSTR parameter must
       reside in the default data segment.

       See also FUNCTION ENCODE.


 PROCEDURE DELETE (VARS D : LSTRING; I, N : INTEGER);

       A string intrinsic procedure. Deletes N characters from D, starting
       with D [I].  An error occurs if an attempt is made to delete more
       characters starting at I than it is possible to delete, i.e., if
       D.LEN < (I + N - 1).


 PROCEDURE DISBIN;

       A library routine (interrupt). Along with ENABIN and VECTIN,
       DISBIN handles interrupt processing. DISBIN disables interrupts;
       ENABIN enables interrupts; VECTIN sets an interrupt vector. The
       effect of these procedures varies with the target machine. See
       Appendix B, "Version Specifics," in the Microsoft Pascal Compiler
       User's Guide for information about your implementation.


 PROCEDURE DISCARD (VAR F);

       A file system procedure (extend level I/O). Closes and deletes an
       open file.

       See Section 16.3.1, "Extend Level Procedures," for a description
       of DISCARD.


 PROCEDURE DISMQQ (BLOCK : ADSMEM);

       A library routine (segmented heap management function). This
       function takes an ADSMEM generated by ALLMQQ or GETMQQ and invokes
       FREMQQ to return the space described by the ADSMEM to the long heap
       memory pool. If errors occur, runtime messages are generated.

       DISMQQ may not be available in your implementation of MS-Pascal.
       See the "Version Specifics" appendix of your Microsoft Pascal
       Compiler User's Guide for details.


 PROCEDURE DISPOSE (VARS P : POINTER);

       A dynamic allocation procedure (short form). Releases the memory
       used for the variable pointed to by P. P must be a valid pointer; it
       may not be NIL, uninitialized, or pointing at a heap item that
       already has been DISPOSEd. These are checked if the NIL check switch
       is on.

       P should not be a reference parameter or a WITH statement record
       pointer, but these errors are not caught. A DISPOSE of a WITH
       statement record can be done at the end of the WITH statement without
       problem.

       If the variable is a super array type or a record with variants,
       you may safely use the short form of DISPOSE to release the variable,
       regardless of whether it was allocated with the long or short form of
       NEW. Using the short form of DISPOSE on a heap variable allocated
       with the long form of NEW is an ISO-defined error not caught in
       MS-Pascal.


 PROCEDURE DISPOSE
 VARS P : POINTER;T1,T2,...TN : TAGS);

       A dynamic allocation procedure (long form). The long form of DISPOSE
       works the same as the short form. However, the long form checks the
       size of the variable against the size implied by the tag field or
       array upper bound values T1, T2, ... Tn. These tag values should be
       the same as defined in the corresponding NEW procedure.

       See also the SIZEOF function, which uses the same array upper
       bounds or tag value parameters to return the number of bytes in a
       variable.


 PROCEDURE ENABIN;

       A library routine (interrupt handling). Along with DISBIN and
       VECTIN, ENABIN handles interrupt processing. ENABIN enables
       interrupts; DISBIN disables interrupts; VECTIN sets an interrupt
       vector. The effect of these procedures may vary with the target
       machine. See Appendix B, "Version Specifics," in the Microsoft
       Pascal Compiler User's Guide for information about your
       implementation.


 FUNCTION ENCODE (VAR LSTR : LSTRING, X : M : N) : BOOLEAN;

       An extend level intrinsic function. Converts the expression X to its
       external ASCII representation and puts this character string into
       LSTR. Returns TRUE, unless the LSTRING is too small to hold the
       string generated. In this case, ENCODE returns FALSE and the value of
       the LSTR is undefined. ENCODE works exactly the same as the WRITE
       procedure, including the use of M and N parameters (see Section
       16.2.4, "WRITE Formats," for a discussion of these parameters).

       X must be one of the types INTEGER, WORD, enumerated, one of
       their subranges, BOOLEAN, REAL4, REAL8, INTEGER4, or a pointer
       (address types need the .R or .S suffix).

       In a segmented memory environment, the LSTR parameter must
       reside in the default data segment.

       See also FUNCTION DECODE.


 PROCEDURE ENDOQQ;

       A library procedure (termination). ENDOQQ is called during
       termination and the default version does nothing. However, you may
       write your own version of ENDOQQ, if you want, to invoke a debugger
       or to write customized messages, such as the time of execution, to a
       terminal screen.

       Since ENDOQQ is called after errors are processed, if ENDOQQ
       itself invokes an error, the result is an infinite termination loop.

       See also PROCEDURE BEGOQQ.


 PROCEDURE ENDXQQ;

       The termination procedure. ENDXQQ is the overall termination
       routine and performs the following actions:

       1.  It calls ENDOQQ.

       2.  It terminates the file system (closing any open files).

       3.  It returns to the target operating system (or whatever called
           BEGXQQ).

       ENDXQQ may be useful for ending program execution from inside a
       procedure or function, without calling ABORT. ENDXQQ corresponds to
       the HALT procedure in other Pascals.


 FUNCTION EOF : BOOLEAN;
 FUNCTION EOF (VAR F) : BOOLEAN;

       A file system function. Indicates whether the current position
       of the file is at the end of the file F for SEQUENTIAL and TERMINAL
       file modes. EOF with no parameters is the same as EOF (INPUT).

       See Section 16.1.3, "EOF and EOLN," for a more complete
       description of EOF.


 FUNCTION EOLN : BOOLEAN;
 FUNCTION EOLN (VAR F) : BOOLEAN;

       A file system function. Indicates whether the current position
       of the file is at the end of a line in the textfile F. EOLN with no
       parameters is the same as EOLN (INPUT).

       See Section 16.1.3, "EOF and EOLN," for a description of EOLN.


 PROCEDURE EVAL (EXPRESSION, EXPRESSION, ... );

       An extend level intrinsic procedure. Evaluates expression
       parameters only, but accepts any number of parameters of any type.
       EVAL is used to evaluate an expression as a statement; it is commonly
       used to evaluate a function for its side effects only, without using
       the function return value.


 FUNCTION EXP (X : NUMERIC) : REAL;

       An arithmetic function. Returns the exponential value of X (i.e.,
       to the X). Both X and the return value are of type REAL. To force a
       particular precision, declare EXSRQQ (CONSTS REAL4) and/or EXDRQQ
       (CONSTS REAL8) and use them instead.


 FUNCTION EXSRQQ (CONSTS A : REAL4) : REAL4;
 FUNCTION EXDRQQ (CONSTS A : REAL8) : REAL8;

       See FUNCTION EXP.


 PROCEDURE FILLC (D : ADRMEM; N : WORD; C : CHAR);

       A system level intrinsic procedure. Fills D with N copies of the
       CHAR C. No bounds checking is done.

       See also PROCEDURE FILLSC for segmented address types. The MOV
       and FILL procedures take value parameters of type ADRMEM and ADSMEM,
       but since all ADR (or ADS) types are compatible, the ADR (or ADS) of
       any variable or constant can be used as the actual parameter. These
       are dangerous but sometimes useful procedures.


 PROCEDURE FILLSC (D : ADSMEM; N : WORD; C : CHAR);

       A system level intrinsic procedure. Fills D with N copies of the CHAR
       C. No bounds checking is done.

       See also PROCEDURE FILLC for relative address types. The MOV
       and FILL procedures take value parameters of type ADRMEM and ADSMEM,
       but since all ADR (or ADS) types are compatible, the ADR (or ADS) of
       any variable or constant can be used as the actual parameter. These
       are dangerous but sometimes useful procedures.


 FUNCTION FLOAT (X : INTEGER) : REAL;

       A data conversion function. Converts an INTEGER value to a REAL
       value.  You normally don't need this function, since INTEGER-to-REAL
       is usually done automatically. However, because FLOAT is needed by
       the runtime package, it is included at the standard level.


 FUNCTION FLOAT4 (X : INTEGER4) : REAL;

       A data conversion function. Converts an INTEGER4 value to a REAL
       value. This type conversion is also done automatically; however, it
       is possible to lose precision. (Losing precision is not an error.)


 FUNCTION FREECT (SIZE : WORD) : WORD;

       A library function. Returns an estimate of the number of times
       NEW could be called to allocate heap variables with length SIZE
       bytes. FREECT takes into account DISPOSE and adjacent free blocks
       and is generally used with the SIZEOF function. However, it does not
       assume any stack space will be needed. Since stack space generally
       will be needed, the value returned should be reduced accordingly.

       Example:

          IF FREECT (SIZEOF (REC, TRUE, 5)) > 2
            THEN DO_SOMETHING


 FUNCTION FREMQQ (BLOCK : ADSMEM) : WORD;

       A library routine (segmented heap management function). This
       function takes an ADSMEM generated by ALLMQQ or GETMQQ and returns
       the space described by the ADSMEM to the long heap memory pool. The
       function returns a word value. If the word value is 0, FREMQQ
       encountered no errors. If the word value is 1, the release of memory
       was in error.

       FREMQQ may not be available on your system; see your Microsoft Pascal
       Compiler User's Guide.


 PROCEDURE GET (VAR F);

       A file system procedure. GET either reads the currently pointed-to
       component of F to the buffer variable F^ and advances the file
       pointer, or sets the buffer variable status to empty.

       See Section 16.1.1, "GET and PUT," for a description of GET.


 FUNCTION GETMQQ (WANTS : WORD) : ADSMEM;

       A library routine (segmented heap management function). This
       function returns a long segmented address of type ADSMEM. GETMQQ
       takes a parameter "wants" that is a memory request in bytes.

       GETMQQ invokes ALLMQQ but in addition, issues error messages if
       ALLMQQ fails. GETMQQ may not be available on your system; see your
       Microsoft Pascal Compiler User's Guide.


 FUNCTION GTYUQQ (LEN : WORD; LOC : ADSMEM) : WORD;

       A library function (terminal I/O). Reads a maximum of LEN
       characters from the terminal keyboard and stores them in memory
       beginning at the address LOC. The return value is the number of
       characters actually read. GTYUQQ always reads the entire line you
       enter. Any characters typed beyond the end of the buffer length are
       lost.

       Example:

           LSTR.LEN := GTYUQQ (UPPER(LSTR), ADS LSTR(1));

       Together with PTYUQQ and PLYUQQ, GTYUQQ is useful for doing
       terminal I/O in a low-overhead environment. These functions are part
       of a collection of routines called Unit U, which implements the MS-
       Pascal file system. (See Section 10.2, "An Overview of the File
       System," in your Microsoft Pascal Compiler User's Guide for further
       information on Unit U.)


 FUNCTION HIBYTE (INTEGER-WORD) : BYTE;

       An extend level intrinsic function. Returns the most significant
       byte of an INTEGER or WORD. Depending on the target processor, the
       most significant byte may be the first or the second addressed byte
       of the word.

       See also FUNCTION LOBYTE.


 FUNCTION HIWORD (INTEGER4) : WORD;

       An extend level intrinsic function. Returns the high-order word of
       the four bytes of the INTEGER4. The sign bit of the INTEGER4 becomes
       the most significant bit of the WORD.

       See also FUNCTION LOWORD.


 PROCEDURE INSERT (CONSTS S : STRING;
 VARS D : LSTRING; I : INTEGER);

       A string intrinsic procedure. Inserts S starting just before D [I].
       An error occurs if D is too small, i.e., if

           UPPER (D) < UPPER (S) + D.LEN + 1

       or if

           D.LEN < I


 FUNCTION LADDOK
 (A, B : INTEGER4; VAR C : INTEGER4) : BOOLEAN;

       A library routine (no-overflow arithmetic). Sets C equal to A plus
       B. One of two functions that do 32-bit signed arithmetic without
       causing a runtime error, even if the arithmetic debugging switch is
       on. Both LADDOK and LMULOK return TRUE if there is no overflow, and
       FALSE if there is. These routines are useful for extended-precision
       arithmetic, or modulo 2^32 arithmetic, or arithmetic based on user
       input data.


 FUNCTION LDSRQQ (CONSTS A : REAL4) : REAL4;
 FUNCTION LDDRQQ (CONSTS A : REAL8) : REAL8;

       Arithmetic functions. Return the logarithm, base 10, of A. Both A
       and the return value are of type REAL4 or REAL8, as shown. These
       functions are from the MS-FORTRAN runtime library and must be
       declared EXTERN before use.


 FUNCTION LMULOK
 (A, B : INTEGER4; VAR C : INTEGER4) : BOOLEAN;

       A library routine (no-overflow arithmetic). Sets C equal to A times
       B. One of two functions that do 32-bit signed arithmetic without
       causing a runtime error on overflow. Normal arithmetic may cause a
       runtime error even if the arithmetic debugging switch is off. Both
       LMULOK and LADDOK return TRUE if there is no overflow, and FALSE if
       there is. These routines are useful for extended-precision
       arithmetic, or modulo 2^32 arithmetic, or arithmetic based on user
       input data.


 FUNCTION LN (X : REAL) : REAL;

       An arithmetic function. Returns the logarithm, base e, of X. Both X
       and the return value are of type REAL. To force a particular
       precision, declare LNSRQQ (CONSTS REAL4) and/or LNDRQQ (CONSTS REAL8)
       and use them instead. An error occurs if X is less than or equal to
       zero.


 FUNCTION LNSRQQ (CONSTS A : REAL4) : REAL4;
 FUNCTION LNDRQQ (CONSTS A : REAL8) : REAL8;

       See FUNCTION LN.


 FUNCTION LOBYTE (INTEGER-WORD) : BYTE;

       An extend level intrinsic function. Returns the least significant
       byte of an INTEGER or WORD. Depending on the target processor,
       the least significant byte may be the first or the second
       addressed byte of the word.

       See also FUNCTION HIBYTE.


 FUNCTION LOCKED (VARS SEMAPHORE : WORD) : BOOLEAN;

       A library function (semaphore). If the semaphore was available,
       LOCKED returns the value TRUE and sets the semaphore unavailable.
       Otherwise, if it was already locked, LOCKED returns FALSE. UNLOCK
       sets the semaphore available. As a binary semaphore, there are only
       two states.

       See also PROCEDURE UNLOCK.


 FUNCTION LOWER (EXPRESSION) : VALUE;

       An extend level intrinsic function. LOWER takes a single parameter
       of one of the following types: array, set, enumerated, or subrange.
       The value returned by LOWER is one of the following:

       1.  the lower bound of an array

       2.  the first allowable element of a set

       3.  the first value of an enumerated type

       4.  the lower bound of a subrange

       LOWER uses the type, not the value, of the expression. The value
       returned by LOWER is always a constant.

       See also FUNCTION UPPER.


 FUNCTION LOWORD (INTEGER4) : WORD;

       An extend level intrinsic function. Returns the low-order WORD
       of the four bytes of the INTEGER4.

       See also FUNCTION HIWORD.


 PROCEDURE MARKAS (VAR HEAPMARK : INTEGER4);

       A library procedure (heap management). Parallels the MARK procedure
       in other Pascals. MARKAS marks the upper and lower limits of the
       heap. The DISPOSE procedure is generally more powerful, but MARKAS
       may be useful for converting from other Pascal dialects.

       In other Pascals, the parameter is of a pointer type. However,
       MS-Pascal needs two words to save the heap limits, since in some
       implementations the heap grows toward both higher and lower
       addresses. The HEAPMARK variable should not be used as a normal
       INTEGER4 number; it should only be set by MARKAS and passed to
       RELEAS.

       To use MARKAS and RELEAS, pass an INTEGER4 variable, M for
       example, as a VAR parameter to MARKAS. MARKAS places the bounds of
       the heap in M. To release heap space, simply invoke the procedure
       with RELEAS (M).

       MARKAS and RELEAS work as intended only if you never call
       DISPOSE.


 FUNCTION MDSRQQ (CONSTS A, B : REAL4) : REAL4;
 FUNCTION MDDRQQ (CONSTS A, B : REAL8) : REAL8;

       Arithmetic functions. A modulo B, defined as:

       MDSRQQ (A, B) = A - AISRQQ (A/B) * B
       MDDRQQ (A, B) = A - AIDRQQ (A/B) * B

       Both A and B are of type REAL4 or REAL8, as shown. These
       functions are from the MS-FORTRAN runtime library and must be
       declared EXTERN before use.


 FUNCTION MEMAVL : WORD;

       A library functioqwn (heap management). Returns the number of
       bytes available between the stack and the heap. MEMAVL acts like the
       MEMAVAIL function in UCSD Pascal. If you have previously used
       DISPOSE, MEMAVL may return a value less than the actual number of
       bytes available.


 FUNCTION MNSRQQ (CONSTS A, B : REAL4) : REAL4;
 FUNCTION MNDRQQ (CONSTS A, B : REAL8) : REAL8;

       Arithmetic functions. Return the value of A or B, whichever is
       smaller. Both A and B are of type REAL4 or REAL8, as shown. These
       functions are from the MS-FORTRAN runtime library and must be
       declared EXTERN before use.

       See also FUNCTION MXSRQQ and FUNCTION MXDRQQ.


 PROCEDURE MOVEL (S, D : ADRMEM; N : WORD);

       A system level intrinsic procedure. Moves N characters (bytes)
       starting at S^ to D^, beginning with the lowest addressed byte of
       each array. Regardless of the value of the range and index checking
       switches, there is no bounds checking.

       Example:

           MOVEL (ADR 'New String Value', ADR V, 16)

       See also PROCEDURE MOVESL for segmented address types. Use
       MOVEL and MOVESL to shift bytes left or when the address ranges do
       not overlap.

       The MOVE and FILL procedures take value parameters of type
       ADRMEM and ADSMEM, but since all ADR (or ADS) types are compatible,
       the ADR (or ADS) of any variable or constant can be used as the
       actual parameter. These are dangerous but sometimes useful
       procedures.


 PROCEDURE MOVER (S, D : ADRMEM; N : WORD);

       A system level intrinsic procedure. Like MOVEL, but starts at the
       highest addressed byte of each array. Use MOVER and MOVESR to shift
       bytes right. As with MOVEL, there is no bounds checking.

       Example:

           MOVER (ADR V[0], ADR V[4], 12)

       See also PROCEDURE MOVESR for segmented address types.

       The MOVEs and FILLs  take value parameters of type ADRMEM and
       ADSMEM, but since all ADR (or ADS) types are compatible, the ADR (or
       ADS) of any variable or constant can be used as the actual parameter.
       These are dangerous but sometimes useful procedures.


 PROCEDURE MOVESL (S, D : ADSMEM; :N : WORD);

       A system level intrinsic procedure. Moves N characters (bytes)
       starting at S^ to D^, beginning with the lowest addressed byte of
       each array. Regardless of the value of the range and index checking
       switches, there is no bounds checking.

       Example:

           MOVESL (ADS 'New String Value', ADS V, 16)

       See also PROCEDURE MOVEL for relative address types. Use MOVEL
       and MOVESL to shift bytes left or when the address ranges do not
       overlap.

       The MOVE and FILL procedures take value parameters of type
       ADRMEM and ADSMEM, but since all ADR (or ADS) types are compatible,
       the ADR (or ADS) of any variable or constant can be used as the
       actual parameter. These are dangerous but sometimes useful
       procedures.


 PROCEDURE MOVESR (S, D : ADSMEM; N : WORD);

       A system level intrinsic procedure. Like MOVESL, but starts at the
       highest addressed byte of each array. Use MOVER and MOVESR to shift
       bytes right. As with MOVESL, there is no bounds checking.

       Example:

           MOVESR (ADS V[0], ADS V[4], 12)

       See also PROCEDURE MOVER for relative address types.

       The MOVE and FILL procedures take value parameters of type
       ADRMEM and ADSMEM, but since all ADR (or ADS) types are compatible,
       the ADR (or ADS) of any variable or constant can be used as the
       actual parameter. These are dangerous but sometimes useful
       procedures.


 FUNCTION MXSRQQ (CONSTS A, B : REAL4) : REAL4;
 FUNCTION MXDRQQ (CONSTS A, B : REAL8) : REAL8;

       Arithmetic functions. Return the value of A or B, whichever is
       larger. Both A and B are of type REAL4 or REAL8, as shown. These
       functions are from the MS-FORTRAN runtime library and must be
       declared EXTERN before use.

       See also FUNCTION MNSRQQ and MNDRQQ.


 PROCEDURE NEW (VARS P : POINTER);

       A library procedure (heap management, short form). Allocates a new
       variable V on the heap and at the same time assigns a pointer to V to
       the pointer variable P (a VARS parameter). The type of V is
       determined by the pointer declaration of P. If V is a super array
       type, use the long form of the procedure instead. If V is a record
       type with variants, the variants giving the largest possible size are
       assumed, permitting any variant to be assigned to P^.


 PROCEDURE NEW (VARS P : POINTER; T1, T2, ... TN : TAGS);

       A library procedure (heap management, long form). Allocates a
       variable with the variant specified by the tag field values T1
       through TN. The tag field values are listed in the order in which
       they are declared. Any trailing tag fields can be omitted.

       If all tag field values are constant, MS-Pascal allocates only
       the amount of space required on the heap, rounded up to a word
       boundary. The value of any omitted tag fields is assumed to be such
       that the maximum possible size is allocated.

       If some tag fields are not constant values, the compiler uses
       one of two strategies:

       1.  It assumes that the first nonconstant tag field and all
           following tags have unknown values, and allocates the maximum
           size necessary.

       2.  It generates a special runtime call to a function that
           calculates the record size from the variable tag values
           available. This depends on the implementation. A similar
           procedure applies to DISPOSE and SIZEOF.

       You should set all tag fields to their proper values after the
       call to NEW and never change them. The compiler does not do any of
       the following:

       1.  assign tag values

       2.  check that they are initialized correctly

       3.  check that their value is not changed during execution

       According to the ISO standard, a variable created with the long
       form of NEW cannot be any of the following:

       1.  used as an expression operand

       2.  passed as a parameter

       3.  assigned a value

       MS-Pascal does not catch these errors. Fields within the record
       can be used normally.

       Assigning a larger record to a smaller one allocated with the
       long form of NEW would wipe out part of the heap. This condition is
       difficult to detect at compile time. Therefore, in MS-Pascal, any
       assignment to a record in the heap that has variants uses the actual
       length of the record in the heap, rather than the maximum length.

       However, an assignment to a field in an invalid variant may
       destroy part of another heap variable or the heap structure itself.
       This error is not caught, unless all tag values are explicit, the tag
       values are correct, and the tag checking switch is on.

       The extend level allows pointers to super arrays. The long form
       form of NEW is used as described above, except that array upper bound
       values are given instead of tag values. All upper bounds must be
       given. Bounds can be constants or expressions; in any case, only the
       size required is allocated.

       The entire array referenced by such a pointer cannot be assigned
       or compared, except that LSTRINGs can always be compared. The entire
       array can be passed as a reference parameter if the formal parameter
       is of the same super array type. Components of the array can be used
       normally.


 FUNCTION ODD (X : ORDINAL) : BOOLEAN;

       A data conversion function. Tests the ordinal value X to see whether
       it is odd. ODD is TRUE only if ORD (X) is odd; otherwise it is
       FALSE.


 FUNCTION ORD (X : VALUE) : INTEGER;

       A data conversion function. Converts to INTEGER any value of one
       of the types shown in the following list according to the rules
       given.

       Type of X        Return value
       
       INTEGER          X

       WORD <= MAXINT   X

       WORD >  MAXINT   X - 2 * (MAXINT + 1)
                        (i.e., same 16 bits
                        as at start!)

       CHAR             ASCII code for X

       Enumerated       Position of X in the
                        type definition,
                        starting with 0

       INTEGER4         Lower 16 bits
                        (i.e., same as
                        ORD (LOWORD (INTEGER4))

       Pointer          Integer value of
                        pointer


 PROCEDURE PACK(CONSTS A : UNPACKED;
 I : INDEX; VARS Z : PACKED);

       A data conversion procedure. Moves elements of an unpacked array to a
       packed array. If A is an ARRAY [M..N] OF T and Z is a PACKED ARRAY
       [U..V] OF T, then PACK (A, I, Z) is the same as:

       FOR J := U TO V DO Z [J] := A [J - U + I]

       In both PACK and UNPACK, the parameter I is the initial index
       within A. The bounds of the arrays and the value of I must be
       reasonable; i.e., the number of components in the unpacked array A
       from I to M must be at least as great as the number of components in
       the packed array Z. The range checking switch controls checking of
       the bounds.


 PROCEDURE PAGE;
 PROCEDURE PAGE (VAR F);

       A file system procedure. Causes skipping to the top of a new page
       when the textfile F is printed. PAGE with no parameter is the same
       as PAGE (INPUT).

       See Section 16.1.4, "PAGE," for a description of PAGE.


 FUNCTION PISRQQ
 (CONSTS A : REAL4; CONSTS B : INTEGER4) : REAL4;
 FUNCTION PIDRQQ
 (CONSTS A : REAL8; CONSTS B : INTEGER4) : REAL8;

       Arithmetic functions. The return value is A**B (A to the INTEGER
       power of B). A is of type REAL4 or REAL8, as shown. B is always of
       type INTEGER4. These functions are from the MS-FORTRAN runtime
       library and must be declared EXTERN before use.


 PROCEDURE PLYUQQ;

       A library routine (terminal I/O). Writes an end-of-line
       character to the terminal screen.

       Together with GETYQQ and PTYUQQ, PLYUQQ is useful for doing
       terminal I/O in a low-overhead environment. These functions are part
       of a collection of routines called Unit U, which implements the
       MS-Pascal file system. (See Section 10.2, "An Overview of the File
       System," in your Microsoft Pascal Compiler User's Guide for further
       information on Unit U.)


 FUNCTION POSITN
 (CONSTS PAT : STRING; CONSTS S : STRING; I : INTEGER) : INTEGER;

       A string intrinsic function. Returns the integer position of the
       pattern PAT in S, starting the search at S [I]. If PAT is not found
       or if I > upper (S), the return value is 0. If PAT is the null
       string, the return value is 1. There are no error conditions.


 FUNCTION PRED (X : ORDINAL) : ORDINAL;

       A data conversion function. Determines the ordinal "predecessor" to
       X. The ORD of the result returned is equal to ORD (X) - 1. An error
       occurs if the predecessor is out of range or overflow occurs. These
       errors are caught if appropriate debug switches are on.


 FUNCTION PRSRQQ (A, B : REAL4) : REAL4;
 FUNCTION PRDRQQ (A, B : REAL8) : REAL8;

       Arithmetic functions. The return value is A**B (A to the REAL power
       of B). Both A and B are of type REAL4 or REAL8, as shown. An error
       occurs if A < 0 (even if B happens to have an integer value). These
       functions are from the MS-FORTRAN runtime library and must be
       declared EXTERN before use.


 PROCEDURE PTYUQQ (LEN : WORD; LOC : ADSMEM);

       A library routine (terminal I/O). Writes LEN characters,
       beginning at LOC in memory, to the terminal screen.

       Example:

           PTYUQQ (8, ADS 'PROMPT:');

       Together with GETYQQ and PLYUQQ, PTYUQQ is useful for doing
       terminal I/O in a low-overhead environment. These functions are part
       of a collection of routines called Unit U, which implements the
       MS-Pascal file system. (See Section 10.2, "An Overview of the File
       System," in your Microsoft Pascal Compiler User's Guide for further
       information on Unit U.)


 PROCEDURE PUT (VAR F);

       A file system procedure. Writes the value of the file buffer
       variable F^ to the currently pointed-to component of F and advances
       the file pointer.

       See Section 16.1.1, "GET and PUT," for a description of PUT.


 PROCEDURE READ (VAR F; P1, P2, ... CR);

       A file system procedure. READ reads data from files. Both READ and
       READLN are defined in terms of the more primitive operation, GET.

       See Section 16.2, "Textfile Input and Output," for a description
       of READ.


 PROCEDURE READFN (VAR F; P1, P2, ... CR);

       A file system procedure (extend level I/O). READFN is the same
       as READ (not READLN) with two exceptions:

       1.  File parameter F should be present (INPUT is assumed but a
           warning is given).

       2.  If a parameter P is of type FILE, a sequence of characters
           forming a valid filename is read from F and assigned to P in
           the same manner as ASSIGN.

       Parameters of other types are read in the same way as the READ
       procedure.

       See Section 16.3.1, "Extend Level Procedures," for a description
       of READFN.


 PROCEDURE READLN (VAR F; P1, P2, ... CR);

       A textfile I/O procedure. At the primitive GET level, without
       parameters, READLN (F) is equivalent to the following:

          BEGIN
            WHILE NOT EOLN (F) DO GET (F);
            GET (F)
          END

       The procedure READLN is very much like READ, except that it reads up
       to and including the end of line.

       See Section 16.2, "Textfile Input and Output," for a description
       of READ.


 PROCEDURE READSET
 (VAR F; VAR L : LSTRING; CONST S : SETOFCHAR);

       A file system procedure (extend level I/O). READSET reads characters
       and puts them into L, as long as the characters are in the set S and
       there is room in L.

       See Section 16.3.1, "Extend Level Procedures," for a description
       of READSET.


 PROCEDURE RELEAS (VAR HEAPMARK : INTEGER4);

       A library routine (heap management). Parallels the RELEASE procedure
       in other Pascals. RELEAS disposes of heap space past the area set
       with a previous MARKAS call. The DISPOSE procedure in MS-Pascal is
       generally more powerful, but RELEAS may be useful for converting from
       other Pascal dialects.

       In other Pascals, the parameter is of a pointer type. However,
       MS-Pascal needs two words to save the heap limits, since in some
       implementations the heap grows toward both higher and lower
       addresses. The HEAPMARK variable should not be used as a normal
       INTEGER4 number;  it should only be set by MARKAS and passed to
       RELEAS.

       To use MARKAS and RELEAS, pass an INTEGER4 variable, M for
       example, as a VAR parameter to MARKAS. MARKAS places the bounds of
       the heap in M. To RELEAS heap space, simply invoke the procedure
       with RELEAS (M).

       MARKAS and RELEAS work as intended only if DISPOSE is never
       called.


 PROCEDURE RESET (VAR F);

       A file system procedure. Resets the current file position to its
       beginning and does a GET (F).

       See Section 16.1.2, "RESET and REWRITE," for a description of
       RESET.


 FUNCTION RESULT (FUNCTION-IDENTIFIER) : VALUE;

       An extend level intrinsic function. Used to access the current
       value of a function; can only be used within the body of the function
       itself or in a procedure or function nested within it.


 FUNCTION RETYPE (TYPE-IDENT, EXPRESSION) : TYPE-IDENT;

       A system level intrinsic function. Provides a generic type escape,
       returns the value of the given expression as if it had the type named
       by the type identifier. The types implied by the type identifier and
       the expression should usually have the same length, but this is not
       required. RETYPE for a structure can be followed by component
       selectors (array index, fields, reference, etc.). RETYPE is a
       "dangerous" type escape and may not work as intended.

       Example:

           TYPE COLOR = (RED, BLUE, GREEN);
                S2    = STRING (2);
           VAR C :CHAR;
               I, J :INTEGER;
               R :REAL4;
               TINT :
           COLOR;
               .
               .
               R := RETYPE (REAL4, 'abcd');
               {Here, a 4-byte string literal is}
               {converted into a real number.}
               {Note that REAL4 numbers also}
               {require 4 bytes.}

               TINT := RETYPE (COLOR, 2)
               {Here, 2 is converted into a color,}
               {which in this case is GREEN.}
               {This is a relatively "safe" use}
               {of the RETYPE function.}

               C := RETYPE (S2, I) [J]
               {Here, I is retyped into a two}
               {character string. Then J selects}
               {a single character of the string}
               {which is assigned to C.}


       There are two other ways to change type in MS-Pascal.

       1.  First, you can declare a record with one variant of each type
           needed, assign an expression to one variant, and then get the
           value back from another variant.  (This is an error not
           caught at the standard level. Note that the relative mapping
           of variables is subject to change between different versions
           of the compiler.)

       2.  Second, you can declare an address variable of the type
           wanted and assign to it the address of any other variable
           (using ADR).

       Each of these methods has its own subtle differences and quirks
       and should be avoided whenever possible.


 PROCEDURE REWRITE (F);

       A file system procedure. Resets the current file position to its
       beginning.

       See Section 16.1.2, "RESET and REWRITE," for a description of
       REWRITE.


 FUNCTION ROUND (X : REAL) : INTEGER;

       An arithmetic function. Rounds X away from zero. X is of type
       REAL4 or REAL8; the return value is of type INTEGER. The effect of
       ROUND on a number with a fractional part of 0.5 varies with the
       implementation.

       Examples:

       ROUND (1.6) is 2
       ROUND (-1.6) is -2

       An error occurs if ABS (X + 0.5) >= MAXINT.


 FUNCTION ROUND4 (X : REAL) : INTEGER4;

       An arithmetic function. Rounds real X away from zero. X is of
       type REAL4 or REAL8; the return value is of type INTEGER4. The
       effect of ROUND4 on a number with a fractional part of 0.5 varies
       with the implementation.

       Examples:

       ROUND4 (1.6) is 2
       ROUND4 (-1.6) is -2

       An error occurs if ABS (X + 0.5) >= MAXINT4.


 FUNCTION SADDOK
 (A, B : INTEGER; VAR C : INTEGER) : BOOLEAN;

       A library routine (no-overflow arithmetic). Sets C equal to A
       plus B. One of two functions that do 16-bit signed arithmetic
       without causing a runtime error on overflow. Normal arithmetic may
       cause a runtime error even if the arithmetic debugging switch is off.
       Both SADDOK and SMULOK return TRUE if there is no overflow, and FALSE
       if there is. These routines can be useful for extended-precision
       arithmetic, or modulo 2^16 arithmetic, or arithmetic based on user
       input data.


 FUNCTION SCANEQ (LEN : INTEGER; PAT : CHAR;
 CONSTS S : STRING; I : INTEGER) : INTEGER;

       A string intrinsic function. Scans, starting at S [I], and
       returns the number of characters skipped. SCANEQ stops scanning when
       a character equal to pattern PAT is found or LEN characters have been
       skipped. If LEN < 0, SCANEQ scans backwards and returns a negative
       number. SCANEQ returns the LEN parameter if it finds no characters
       equal to pattern PAT found or if I > UPPER (S). There are no error
       conditions.


 FUNCTION SCANNE (LEN : INTEGER; PAT : CHAR;
 CONSTS S : STRING; I : INTEGER) : INTEGER;

       A string intrinsic function. Like SCANEQ, but stops scanning
       when a character not equal to pattern PAT is found.

       SCANNE stops scanning when a character not equal to pattern PAT is
       found or LEN characters have been skipped. If LEN < 0, SCANNE scans
       backwards and returns a negative number. SCANNE returns LEN
       parameter if it finds all characters equal to pattern PAT found or if
       I > UPPER (S). There are no error conditions.


 PROCEDURE SEEK (VAR F; N : INTEGER4);

       A file system procedure (extend level I/O). In contrast to normal
       sequential files, DIRECT files are random access structures. SEEK is
       used to randomly access components of such files.


 FUNCTION SHSRQQ (CONSTS A : REAL4) : REAL4;
 FUNCTION SHDRQQ (CONSTS A : REAL8) : REAL8;

       Arithmetic functions. Return the hyperbolic sine of A. A is of type
       REAL4 or REAL8, as shown. These functions are from the MS-FORTRAN
       runtime library and must be declared EXTERN before use.


 FUNCTION SIN (X : NUMERIC) : REAL;

       An arithmetic function. Returns the sine of X in radians. Both X and
       the return value are of type REAL. To force a particular precision,
       declare SNSRQQ (CONSTS REAL4) and/or SNDRQQ (CONSTS REAL8) and use
       them instead.


 FUNCTION SIZEOF (VARIABLE) : WORD;
 FUNCTION SIZEOF (VARIABLE, TAG1,
 TAG2, ... TAGN) : WORD;

       An extend level intrinsic function. Returns the size of a variable
       in bytes. Tag values or array upper bounds are set as in
       the NEW and DISPOSE functions. If the variable is a record with
       variants, and the first form is used, the maximum size possible is
       returned. If the variable is a super array, the second form, which
       gives upper bounds, must be used.


 FUNCTION SMULOK
 (A, B : INTEGER; VAR C : INTEGER) : BOOLEAN;

       A library routine (no-overflow arithmetic function). Sets C equal to
       A times B. One of two functions that do 16-bit signed arithmetic
       without causing a runtime error on overflow. Normal arithmetic may
       cause a runtime error, even if the arithmetic debugging switch is
       off. Each routine returns TRUE if there is no overflow, and FALSE if
       there is. These routines can be useful for extended-precision
       arithmetic, or modulo 2^16 arithmetic, or arithmetic based on user
       input data.


 FUNCTION SNSRQQ (CONSTS A : REAL4) : REAL4;
 FUNCTION SNDRQQ (CONSTS A : REAL8) : REAL8;

       See Function SIN.


 FUNCTION SQR (X : NUMERIC) : NUMERIC;

       An arithmetic function. Returns the square of X, where X is of
       type REAL, INTEGER, WORD, or INTEGER4.


 FUNCTION SQRT (X) : REAL

       An arithmetic function. Returns the square root of X, where X is
       of type REAL. To force a particular precision, declare SRSRQQ
       (CONSTS REAL4) and/or SRDRQQ (CONSTS REAL8) and use them instead. An
       error occurs if X is less than 0.


 FUNCTION SRSRQQ (CONSTS A : REAL4) : REAL4;
 FUNCTION SRDRQQ (CONSTS A : REAL8) : REAL8;

       See also Function SQRT.


 FUNCTION SUCC (X : ORDINAL) : ORDINAL;

       A data conversion function. Determines the ordinal "successor" to X.
       The ORD of the returned result is equal to ORD (X) + 1. An error
       occurs if the successor is out of range or overflow occurs. These
       errors are caught if appropriate debug switches are on.


 FUNCTION THSRQQ (CONSTS A : REAL4) : REAL4;
 FUNCTION THDRQQ (CONSTS A : REAL8) : REAL8;

       Arithmetic functions. Return the hyperbolic tangent of A. Both A and
       the return value are of type REAL4 or REAL8, as shown. These
       functions are from the MS-FORTRAN runtime library and must be
       declared EXTERN before use.


 FUNCTION TICS : WORD;

       A library routine (clock function). If available, TICS returns
       the value of an operating system timing location. The result is in a
       time interval, such as hundredths of a second, depending on the
       target operating system.


 PROCEDURE TIME (VAR S : STRING);

       A library routine (clock function). If available, this procedure
       assigns the current time to its STRING (or LSTRING) variable. If the
       parameter is an LSTRING, you must set the length before you call the
       TIME procedure. The format depends on the target operating system.

       See also PROCEDURE DATE.


 FUNCTION TNSRQQ (CONSTS A : REAL4) : REAL4;
 FUNCTION TNDRQQ (CONSTS A : REAL8) : REAL8;

       Arithmetic functions. Return the tangent of A. Both A and the return
       value are of type REAL4 or REAL8, as shown. These functions are from
       the MS-FORTRAN runtime library and must be declared EXTERN before
       use.


 FUNCTION TRUNC (X : REAL) : INTEGER;

       An arithmetic function. Truncates X toward zero. X is of type
       REAL4 or REAL8, and the return value is of type INTEGER.

          TRUNC (1.6) is 1
          TRUNC (-1.6) is -1

       An error occurs if ABS (X - 1.0) >= MAXINT.


 FUNCTION TRUNC4 (X : REAL) : INTEGER4;

       An arithmetic function. Truncates real X toward zero. X is of
       type REAL4 or REAL8, and the return value is of type INTEGER4.

          TRUNC4 (1.6) is 1
          TRUNC4 (-1.6) is -1

       An error occurs if ABS (X - 1.0) >= MAXINT4.


 FUNCTION UADDOK (A, B : WORD; VAR C : WORD) : BOOLEAN;

       A library routine (no-overflow arithmetic function). Sets C equal to
       A plus B. One of two functions that do 16-bit unsigned arithmetic
       without causing a runtime error on overflow. Normal arithmetic may
       cause a runtime error even if the arithmetic debugging switch is off.
       The following is the binary carry resulting from this addition of A
       and B:

          WRD (NOT UADDOK (A, B, C))

       Both UADDOK and UMULOK return TRUE if there is no overflow and FALSE
       if there is. These routines are useful for extended-precision
       arithmetic, or modulo 2^16 arithmetic, or arithmetic based on user
       input data.


 FUNCTION UMULOK (A, B : WORD; VAR C : WORD) : BOOLEAN;

       A library routine (no-overflow arithmetic function). Sets C equal to
       A times B. One of two functions that do 16-bit unsigned arithmetic
       without causing a runtime error on overflow. Normal arithmetic may
       cause a runtime error even if the arithmetic debugging switch is off.
       Each routine returns TRUE if there is no overflow and FALSE if there
       is. These routines are useful for extended-precision arithmetic, or
       modulo 2^16 arithmetic, or arithmetic based on user input data.


 PROCEDURE UNLOCK (VARS SEMAPHORE : WORD);

       A library routine (semaphore procedure). UNLOCK sets the
       semaphore available. As a binary semaphore, there are only two
       states. UNLOCK can be called any number of times and can be used to
       initialize the semaphore.

       See also FUNCTION LOCKED.


 PROCEDURE UNPACK
 (CONSTS Z : PACKED; VARS A : UNPACKED; I : INDEX);

       A data conversion procedure. Moves elements from packed array to an
       unpacked array. If A is an ARRAY [M..N] OF T, and Z is a PACKED
       ARRAY [U..V] OF T then the above call is the same as:

          FOR J := U TO V DO A [J - U + I] := Z [J]

       In both PACK and UNPACK, the parameter I is the initial index within
       A. The bounds of the arrays and the value of I must be reasonable;
       i.e., the number of components in the unpacked array A from I to M
       must be at least as great as the number of components in the packed
       array Z. The range checking switch controls checking of the bounds.

       See also PROCEDURE PACK


 FUNCTION UPPER (EXPRESSION) : VALUE;

       An extend level intrinsic function. UPPER, like LOWER, takes a
       single parameter of one of the following types: array, set,
       enumerated, or subrange. The value returned by UPPER is one of the
       following:

       1.  the upper bound of an array

       2.  the last allowable element of a set

       3.  the last value of an enumerated type

       4.  the upper bound of a subrange

       The value returned by UPPER is always a constant, unless the
       expression is of a super array type. In this case, the actual upper
       bound of the super array type is returned. Note that the type and
       not the value of the expression is used for UPPER.

       See also FUNCTION LOWER.


 PROCEDURE VECTIN (V : WORD; PROCEDURE I [INTERRUPT]);

       A library routine (interrupt handling procedure). One of three
       procedures for processing interrupts. VECTIN sets an interrupt
       vector, so that interrupts of type V are connected to procedure I.
       (ENABIN enables interrupts and DISBIN disables interrupts.) The
       effect of these procedures and the meaning of V varies with the
       target machine. See Appendix B, "Version Specifics," in the
       Microsoft Pascal Compiler User's Guide for information regarding your
       implementation.


 FUNCTION WRD (X : VALUE) : WORD;

       A data conversion procedure. Converts to WORD any of the types shown
       in the following list according to the rules given.

           Type of X      Return Value
           
           WORD           X

           INTEGER >= 0   X

           INTEGER < 0    X + MAXWORD + 1
                          (i.e., same 16 bits
                          as at start!)

           CHAR           ASCII code for X

           Enumerated     Position of X in the
                          type definition,
                          starting with 0

           INTEGER4       Lower 16 bits
                          (i.e., same as
                          LOWORD(INTEGER4))

           Pointer        Word value of pointer


 PROCEDURE WRITE (VAR F; P1, P2, ... CR);
 PROCEDURE WRITELN (VAR F; P1, P2, ... CR);

       File system level intrinsic procedures. WRITEs data to files.
       WRITE and WRITELN are defined in terms of the more primitive
       operation PUT. WRITELN is the same as WRITE, except it also writes
       an end-of-line.

       See Section 16.2.3, "WRITE and WRITELN," for descriptions of
       these procedures.



 Chapter 16  File-Oriented Procedures and Functions

 

 16.1  File System Primitive Procedures and Functions

        16.1.1  GET and PUT

        16.1.2  RESET and REWRITE

        16.1.3  EOF and EOLN

        16.1.4  PAGE

        16.1.5  Lazy Evaluation

        16.1.6  Concurrent I/O

 16.2  Textfile Input and Output

        16.2.1  READ and READLN

        16.2.2  READ Formats

        16.2.3  WRITE and WRITELN

        16.2.4  WRITE Formats

 16.3  Extend Level I/O

        16.3.1  Extend Level Procedures

        16.3.2  Temporary Files



 Chapter 14, "Introduction to Procedures and Functions," introduced you to
 procedures and functions in general and described their use and
 construction.

 Chapter 15, "Available Procedures and Functions," described eight
 categories of procedures and functions that are available to you either
 because they are predeclared or because they are part of the Microsoft
 Pascal runtime libraries. All except those that relate to file input and
 output were discussed in detail.

 This chapter, Chapter 16, "File-Oriented Procedures and Functions,"
 discusses all of the file I/O procedures and functions, as well as lazy
 evaluation and concurrent I/O, two special MS-Pascal features that
 facilitate your use of files.

 The MS-Pascal file system supports a variety of procedures and
 functions that operate on files of different modes and structures.  These
 procedures and functions can be categorized as shown in Table 16.1.


 Table 16.1
 File System Procedures and Functions
ķ
 Category       Procedures   Functions
 
 Primitive      GET          EOF
                PAGE         EOLN
                PUT
 Category       Procedures   Functions
               PUT
                RESET
                REWRITE

 Textfile I/O   READ
                READLN
                WRITE
                WRITELN

 Extend         ASSIGN
 Level I/O      CLOSE
                DISCARD
                READSET
                READFN
                SEEK


 16.1  File System Primitive Procedures and Functions


 This section describes the seven primitive file system procedures and
 functions, which perform file I/O at the most basic level.  Later,
 descriptions of READ and WRITE procedures are defined in terms of the
 primitives GET and  PUT. Two related topics are also discussed in this
 section: lazy evaluation and concurrent I/O.  In all descriptions which
 follow, F is a file parameter (files are always reference parameters), and
 F^ is the buffer variable.

 In a segmented environment, all file variables operated on by these
 procedures must reside in the default data segment. This restriction
 increases the efficiency of file system calls.

     1.  GET and PUT

         The primitive procedures GET and PUT read to and write from
         the buffer variable F^.  GET assigns the next component of a file
         to the buffer variable. PUT performs the inverse operation and
         writes the value of the buffer variable to the next component of
         the file F.

     2.  RESET and REWRITE

         The procedures RESET and REWRITE set the current position of a
         file to its beginning. RESET prepares for later GET and READ
         procedures.  REWRITE prepares for later PUT and WRITE procedures.

     3.  EOF and EOLN

         The functions EOF and EOLN are used to check for the end-of-
         file and end-of-line conditions. They return a BOOLEAN result. In
         general, these values indicate when to stop reading a line or a
         file.

     4.  PAGE

         The procedure PAGE helps in formatting textfiles.  It is not a
         necessary procedure in the same sense as GET and PUT.


 16.1.1  GET and PUT


 The primitive procedures GET and PUT are used to read to and write from the
 buffer variable, F^.  GET assigns the next component of a file to the
 buffer variable. PUT performs the inverse operation and writes the value of
 the buffer variable to the next component of the file F.


 PROCEDURE GET (VAR F);

       A primitive file system intrinsic procedure. If there is a next
       component in the file F, then:

       1.  The current file position is advanced to the next component.

       2.  The value of this component is assigned to the buffer
           variable F^.

       3.  EOF (F) becomes FALSE.

       Advancing and assigning may be deferred internally, depending on
       the mode of the file.

       If no next component exists, then EOF (F) becomes TRUE and the
       value of F^ becomes undefined.  EOF (F) must be FALSE before GET (F),
       since reading past the end of file produces a runtime error. However,
       if F has mode DIRECT, EOF (F) can be TRUE or FALSE, since DIRECT mode
       permits repeated GET operations at the end of the file.  If F^ is a
       record with variants, the compiler reads the variant with the maximum
       size.


 PROCEDURE PUT (VAR F);

       A primitive file system intrinsic procedure.  Writes the value of the
       file buffer variable F^ at the current file position and then
       advances the position to the next component.

       1.  For SEQUENTIAL and TERMINAL mode files, PUT is permitted if
           the previous operation on F was a REWRITE, PUT, or other
           WRITE procedure, and if it was not a RESET, GET, or other
           READ procedure.

       2.  For DIRECT mode files, PUT may occur immediately after a
           RESET or GET.

       Exceptions to these rules cause errors to be generated.  The
       value of F^ always becomes undefined after a PUT.

       In MS-Pascal, the value of F^ after a PUT (F) may vary,
       depending on the target operating system and type of file.  EOF (F)
       must be TRUE before PUT (F), unless F is a DIRECT mode file.  EOF (F)
       is always TRUE after PUT (F).  If F^ is a record with variants, the
       variant with the maximum size is written.


 16.1.2  RESET and REWRITE


 The procedures RESET and REWRITE are used to set the current position of a
 file to its beginning. RESET is used to prepare for later GET and READ
 operations. REWRITE is used to prepare for later PUT and WRITE operations.


 PROCEDURE RESET (VAR F);

       A primitive file system intrinsic procedure.  Resets the current file
       position to its beginning and does a GET (F).  If the file is not
       empty, the first component of F is assigned to the buffer variable
       F^, and EOF (F) becomes false.  If the file is empty, the value of F^
       is undefined and EOF (F) becomes  true.  RESET initializes a file F
       prior to its being read.  For DIRECT files, writing can be done after
       RESET as well.

       In MS-Pascal, a RESET closes the file and then opens it in a way
       that is dependent on the operating system.  An error occurs if the
       filename has not been set (as a program parameter or with ASSIGN or
       READFN) or if the file cannot be found by the operating system.  If
       an error occurs during RESET, the file is closed, even if the file
       was opened correctly and the error came with the initial GET.

       RESET (INPUT) is done automatically when a program is
       initialized, but is also allowed explicitly.  RESET on a file with
       mode DIRECT allows either reading or writing, but the file is not
       created automatically.  Also, the initial GET reads record number one
       on a DIRECT mode file.

       Note that an explicit GET (F) immediately following a RESET (F)
       assigns the second component of the file to the buffer variable.
       However, a READ (F, X) following a RESET (F) sets X to the first
       component of F, since READ (F, X) is "X := F^; GET (F)".


 PROCEDURE REWRITE (VAR F);

       A primitive file system intrinsic procedure.  Positions the current
       file to its beginning.  The value of F^ is undefined and EOF (F)
       becomes TRUE.  This is needed to initialize a file F before writing
       (for DIRECT files, reading can be done after REWRITE too).

       In MS-Pascal, a REWRITE closes the file and then opens it in a
       way that is dependent on the operating system.  If the file does not
       exist in the operating system, it is created. If it does exist, its
       old value is lost (unless it has mode DIRECT).  The filename must
       have been set (as a program parameter or with ASSIGN or READFN).  If
       an error occurs during REWRITE, the file is closed.  If possible, an
       existing file with the same name is not affected when a REWRITE error
       occurs, but with some target operating systems the existing file may
       be deleted.

       REWRITE (OUTPUT) is done automatically when a program is
       initialized, but can also be done explicitly if desired.  REWRITE on
       a DIRECT mode file allows both reading and writing.  REWRITE does not
       do an initial PUT the way RESET does an initial GET.


 16.1.3  EOF and EOLN


 The functions EOF and EOLN check for end-of-file and end-of-line
 conditions, respectively. They return a BOOLEAN result. In general, these
 values indicate when to stop reading a line or a file.


 FUNCTION EOF : BOOLEAN;
 FUNCTION EOF (VAR F) : BOOLEAN;

       A primitive file system intrinsic function.  Indicates whether
       the buffer variable F^ is positioned at the end of the file F for
       SEQUENTIAL and TERMINAL file modes. Therefore, if EOF (F) is TRUE,
       either the file is being written or the last GET has reached the end
       of the file.

       With the DIRECT file mode, if EOF (F) is TRUE, either the last
       operation was a WRITE (the file may or may not be positioned at the
       end in this case) or the last GET reached the end of the file.

       EOF without a parameter is equivalent to EOF (INPUT).
       EOF (INPUT) is generally never TRUE, except in some operating systems
       where a particular terminal character generates an end-of-file
       status, or if INPUT is reassigned to another file.  Calling the
       EOF (F) function accesses the buffer variable F^.


 FUNCTION EOLN : BOOLEAN;
 FUNCTION EOLN  (VAR F) : BOOLEAN;

       A primitive file system intrinsic function.  Indicates whether
       the current position of the file is at the end of a line in the
       textfile F after a GET (F).  The file must have ASCII structure.

       According to the ISO standard, calling EOLN (F) when EOF (F) is
       TRUE is an error.  In MS-Pascal, this error is caught in most cases.
       The file F must be a file of type TEXT.

       If EOLN (F) is TRUE, the value of F^ is a space, but the file is
       positioned at a line marker.  EOLN without a parameter is equivalent
       to EOLN (INPUT).  Calling the EOLN (F) function accesses the buffer
       variable F^.


 16.1.4  PAGE


 The procedure PAGE helps in formatting textfiles. It is not a "necessary"
 procedure in the same sense as GET and PUT.


 PROCEDURE PAGE;
 PROCEDURE PAGE (VAR F);

       A primitive file system intrinsic procedure.  Causes skipping to the
       top of a new page when the textfile F is printed. Since PAGE writes
       to the file, the initial conditions described for PUT must be TRUE.
       The file must have ASCII structure. PAGE without a parameter is
       equivalent to PAGE (OUTPUT).

       If F is not positioned at the start of a line, PAGE (F) first
       writes a line marker to F.  If F has mode SEQUENTIAL or DIRECT, then
       PAGE (F) writes a form feed, CHR (12).  If F has mode TERMINAL, the
       effect is defined by the target operating system interface, which
       will usually also write a form feed.


 16.1.5  Lazy Evaluation


 Lazy evaluation is designed to solve a recurring problem in Pascal,
 specifically, how to READ from a terminal in a natural way.

 The underlying problem is that the ISO standard defines the procedure
 RESET with an initial GET.  Although acceptable in Pascal's original batch
 processing, sequential file environment, this kind of read-ahead doesn't
 work for interactive I/O.

 Lazy evaluation in MS-Pascal provides for deferring actual physical
 input (textfiles only) when a buffer variable is evaluated.

 For example, if a normal file is RESET and then READ, the RESET
 procedure calls the GET procedure, which sets the buffer variable to the
 first component of the file. However, if the file is a terminal, this first
 component does not yet exist!

 Therefore, at a terminal, you must first type a character to
 accommodate the GET procedure. Only then would you be prompted for any
 input.

 Lazy evaluation eliminates this problem for textfiles by giving
 the file's buffer variable a special status value that is either "full" or
 "empty."

 The normal condition after a GET (F) is empty. The status is full
 after a buffer variable has been assigned to or assigned from.  Full
 implies that the buffer variable value is equal to the currently pointed-to
 component.  Empty implies just the opposite, that the buffer variable value
 does not equal the value of the currently pointed-to component and input to
 the buffer variable has been deferred. Table 16.2 summarizes these rules.


 Table 16.2
 Lazy Evaluation
ķ
            Status                               Status
 Statement  at call  Action                      on exit
 
 GET (F)    Full     Point to next file com-     Empty
                     ponent. Becomes EMPTY
                     since value pointed to is
                     not in buffer variable.

 GET (F)    Empty    Load buffer variable with   Empty
                     current file component,
                     then point to next file
            Status                               Status
 Statement  at call  Action                      on exit
                    then point to next file
                     component. Becomes EMPTY
                     since value pointed to is
                     not in buffer variable.

 Reference  Full     No action required.         Full
   to F^

 Reference  Empty    Load buffer variable with   Full
   to F^             current file component.

 Note that RESET (F) first sets the status full and then calls GET, which
 sets the status to empty without any physical input.

 Example of lazy evaluation with automatic REWRITE call:

      {INPUT is automatically a textfile.}
      {RESET (INPUT); done automatically.}
      WRITE (OUTPUT, "Enter number: ");
      READLN (INPUT, FOO);

 The automatic initial call to the RESET procedure calls a GET
 procedure, which changes the buffer variable status from full to empty. The
 first physical action to the terminal is the prompt output from the WRITE.
 READLN does a series of the following operations:

     temp := INPUT^;
     GET (INPUT)

 Physical input occurs when each INPUT^ is fetched and the GET
 procedure sets the status back to empty.

 READLN ends with the sequence:

     WHILE NOT EOLN DO GET (INPUT);
     GET (INPUT)

 This operation skips trailing characters and the line marker. The
 EOLN function invokes the physical input. Entering the carriage return sets
 the EOLN status. Both the GET procedure in the WHILE loop and the trailing
 GET set the status back to empty. The last physical input in the sequence
 above is reading the carriage return.


 16.1.6  Concurrent I/O


 On operating systems that support it, concurrent I/O permits a GET or
 PUT procedure to initiate the I/O and immediately return to the calling
 program. It is only used for BINARY structure files.

 The program can do computation while the buffer variable is being
 filled or emptied. The buffer variable has another special status value
 that can be "ready" or "busy."  If the status is busy when the buffer
 variable needs to be accessed, the program must wait until the status
 becomes ready.

 For example, the following program fragment reads the file IN_FILE,
 does some computation with the current value, and then writes it to the
 file OUT_FILE:

      WHILE NOT EOF (IN_FILE) DO
        {Check for end of input and}
        {wait until IN_FILE is ready.}

      BEGIN
        READ (IN_FILE, BUFF);
        {IN_FILE is ready, so assign it to BUFF;}
        {start reading next component.}

        OPERATE (BUFF);
        {Go process value during READ and WRITE.}

        WRITE (OUT_FILE, BUFF)
        {Wait until OUT_FILE is ready,}
        {then assign BUFF and start writing.}

      END

 The preceding example uses READ and WRITE procedures. Note that the
 following two lines are equivalent:

      READ (IN_FILE, BUFF)
      BUFF := IN_FILE^;  GET (IN_FILE)

 So are these two:

      WRITE (OUT_FILE, BUFF)
      OUT_FILE^ := BUFF; PUT (OUT_FILE)

 Concurrent I/O applies to the procedures GET and PUT, as well as to
 the procedures READ and WRITE.  In practice, it is unusual for the
 Microsoft Pascal runtime system to handle concurrency. See Appendix B,
 "Version Specifics," in the Microsoft Pascal Compiler User's Guide for
 information regarding your implementation.

 When accessing the buffer variable, either for lazy evaluation or
 concurrency, MS-Pascal generates an I/O system call. However, if the buffer
 variable is an actual reference parameter, the procedure or function using
 that parameter can do I/O to the same file, and these special calls cannot
 be executed.

 Passing any buffer variable as a reference parameter is an error in
 MS-Pascal, although only a warning is given. Calling GET or PUT has an
 undefined effect on a file buffer variable accessed indirectly through a
 reference parameter. Assigning the address of a buffer variable to an
 address type variable is equally dangerous, since this bypasses the lazy
 evaluation and concurrency mechanisms.


 16.2  Textfile Input and Output


 Human-readable input and output in standard Pascal are done with
 textfiles. Textfiles are files of type TEXT and always have ASCII
 structure. Normally, the standard textfiles INPUT and OUTPUT are given as
 program parameters in the PROGRAM heading:

      PROGRAM IN_AND_OUT (INPUT, OUTPUT);

 Other textfiles usually represent some input or output device such as
 a terminal, a card reader, a line printer, or an operating system disk
 file.  The extend level permits using additional files not given as program
 parameters.

 In order to facilitate the handling of textfiles, the four standard
 procedures READ, READLN, WRITE, and WRITELN are provided in addition to the
 procedures GET and PUT.

     1.  READ and READLN

         The procedures READ and READLN read data from textfiles. READ
         and READLN are defined in terms of the more primitive operation,
         GET.  The procedure READLN is very much like READ, except that it
         reads up to and including the end-of-line.

     2.  WRITE and WRITELN

         The procedures WRITE and WRITELN write data to textfiles.
         WRITE and WRITELN are defined in terms of the more primitive
         operation, PUT.  The procedure WRITELN writes a line marker to the
         end of a line. In all other respects, WRITELN is analogous to
         WRITE.

 These procedures are more flexible in the syntax for their parameter
 lists, allowing, among other things, for a variable number of parameters.
 Moreover, the parameters need not necessarily be of type CHAR, but can also
 be of certain other types, in which case the data transfer is accompanied
 by an implicit data conversion operation.  In some cases, parameters can
 include additional formatting values that affect the data conversions used.

 If the first variable is a file variable, then it is the file to be
 read or written. Otherwise, the standard files INPUT and OUTPUT are
 automatically assumed as default values in the cases of reading and
 writing, respectively.

 These two files have TERMINAL mode and ASCII structure and are
 predeclared as:

     VAR INPUT, OUTPUT: TEXT;

 In MS-Pascal, the files INPUT and OUTPUT are treated like other
 textfiles. They can be used with ASSIGN, CLOSE, RESET, REWRITE, and the
 other procedures and functions. However, even if present as program
 parameters, they are not initialized with a filename.  Instead, they are
 assigned to the user's terminal.  RESET of INPUT and REWRITE of OUTPUT are
 done automatically, whether or not they are present as program parameters.

 Textfiles represent a special case among file types insofar as they
 are structured into lines by "line markers."  If, upon reading a textfile
 F, the file position is advanced to a line marker (i.e., past the last
 character of a line), then the value of the buffer variable F^ becomes a
 blank, and the standard function EOLN (F) yields the value true.  For
 example:

      +---+---+---+---+---+---+---+---+---+---+---+
      |'L'|'I'|'N'|'E'|'O'|'F'|'T'|'E'|'X'|'T'|   |
      +---+---+---+---+---+---+---+---+---+---+---+
                                                
                                                
                {EOLN = TRUE} {F^ = ' '}

 Advancing the file position once more causes one of three things to
 happen:

     1.  If the end of the file is reached, then EOF (F) becomes TRUE.

     2.  If the next line is empty, a blank is assigned to F^ and EOLN (F)
         remains TRUE.

     3.  Otherwise, the first character of the next line is assigned to F^
         and EOLN (F) is set to FALSE.

 Since line markers are not elements of type CHAR in standard Pascal,
 they can, in theory, only be generated by the procedure WRITELN.  However,
 in MS-Pascal, an actual character may be used for the line marker.  It may,
 therefore, be possible to WRITE a line marker, but not to READ one.

 When a textfile being written is closed, a final line marker is
 automatically appended to the last line of any nonempty file in which the
 last character is not already a line marker.

 When a textfile being read reaches the end of a nonempty file, a line
 marker for the last line is returned even if one was not present in the
 file. Therefore, lines in a textfile always end with a line marker.

 Any list of data written by a WRITELN is usually readable with the
 same list in a READLN (unless an LSTRING occurs that is not on the end of
 the list).

 Interactive prompt and response is very easy in MS-Pascal.  To have
 input on the same line as the response, use WRITE for the prompt. READLN
 must always be used for the response.  For example:


      WRITE ('Enter command: ');

      READLN (response);

 If no file is given, most of the textfile procedures and functions
 assume either the INPUT file or the OUTPUT file.  For example, if I is of
 type INTEGER, then READ (I) is the same as READ (INPUT, I).


 16.2.1  READ and READLN


 PROCEDURE READ
 PROCEDURE READLN

       File system intrinsic procedures for textfile I/O. READ and READLN
       read data from textfiles. Both are defined in terms of the more
       primitive operation, GET. That is, if P is of type CHAR, then
       READ (F, P) is equivalent to:

           BEGIN
              P := F^;
              {Assign buffer variable F^ to P.}
              GET (F)
              {Assign next component of file to F^.}
           END

       READ can take more than a single parameter, as in
       READ (F, P1, P2, ... Pn). This is equivalent to the following:

           BEGIN
              READ (F, P1);
              READ (F, P2);
                .
                .
              READ (F, Pn)
           END

       The procedure READLN is very much like READ, except that it
       reads up to and including the end-of-line.  At the primitive GET
       level, without parameters, READLN is equivalent to the following:

           BEGIN
             WHILE NOT EOLN (F) DO GET (F);
             GET (F)
           END

       A READLN with parameters, as in READLN (F, P1, P2, ... Pn), is
       equivalent to the following:

           BEGIN
              READ (F, P1, P2, Pn);
              READLN (F)
           END

       READLN is often used to skip to the beginning of the next line.
       It can only be used with textfiles (ASCII mode).

       If no other file is specified, both READ and READLN read from
       the standard INPUT file. Therefore, the name INPUT need not be
       designated explicitly. For example, these two READ statements perform
       identical actions:

           READ (P1, P2, P3)
           {Reads INPUT by default}
           READ (INPUT, P1, P2, P3)

       At the standard level, parameters P1, P2, and P3 above must be
       of one of the following types:

           CHAR
           INTEGER
           REAL

       The extend level also allows READ variables of the following
       types:

           WORD
           an enumerated type
           BOOLEAN
           INTEGER4
           a pointer type
           STRING
           LSTRING

       When the compiler reads a variable of a subrange type, the value read
       must be in range. Otherwise, an error occurs, regardless of the
       setting of the range checking switch.

       The procedure READ can also read from a file that is not a
       textfile (e.g., has BINARY mode). The form READ (F, P1, P2, ... Pn)
       can be used on a BINARY file.  However, this READ will not work as
       expected after a SEEK on a DIRECT mode file. For BINARY files,
       READ (F, X) is equivalent to:

           BEGIN
              X := F^;
              GET (F)
           END


 16.2.2  READ Formats


 The READ process for formatted types (everything except CHAR, STRING,
 and LSTRING) first reads characters into an internal LSTRING and then
 decodes the string to get the value.

 Three important points apply to formatted reads:

     1.  Leading spaces, tabs, form feeds, and line markers are skipped.
         For example, when doing READLN (I, J, K) where I, J, and K are
         integers, the numbers can all be on the same line or spread
         over several lines.

     2.  Characters are read as long as they are in the set of
         characters valid for the type wanted. For example, "-1-2-3" is
         read as the string of characters for a single INTEGER, but
         gives an error when the string is decoded. This means that
         items should be separated by spaces, tabs, line markers, or
         characters not permitted in the format.

     3.  M and N values in READ are ignored, except as noted for an N
         value with enumerated types. M and N parameters are not
         accepted in BINARY reads.

 Most of the formatting rules below apply to the function DECODE, as
 well.

     1.  INTEGER and WORD types

         If P is of type INTEGER, WORD, or a subrange thereof, then
         READ (F, P) implies reading a sequence of characters from F which
         form a number according to the normal Pascal syntax, and then
         assigning the number to P. Nondecimal notation (16#C007, 8#74,
         10#19, 2#101, #Face) is accepted for both INTEGER and WORD, with a
         radix of 2 through 36. If P is of an INTEGER type, a leading plus
         (+) or minus (-) sign is accepted. If P is of a WORD type, then
         numbers up to MAXWORD are accepted (32768..65535).

     2.  REAL and INTEGER4 types

         If P is of type REAL, or at the extend level type INTEGER4, READ
         (F, P) implies reading a sequence of characters from F that form a
         number of the appropriate type and assigning the number to P.
         Nondecimal notation is not accepted for REAL numbers, but is
         accepted for INTEGER4 numbers. When reading a REAL value, a number
         with a leading or trailing decimal point is accepted, even though
         this form gives a warning if used as a constant in a program.

     3.  Enumerated and Boolean types

         At the extend level, if P is an enumerated type or BOOLEAN, a
         number is read as a WORD subrange and a value assigned to P such
         that the number is the ORD of the enumerated type's value. In
         addition, if P is of type BOOLEAN, reading one of the character
         sequences 'TRUE' or 'FALSE' cause true and false, respectively, to
         be assigned to P.  The number read must be in the range of the ORD
         values of the variable.

         Also at the extend level, if the parameter P is an enumerated
         type and includes the :N notation as in READ (P::N),
         characters are read from the file F that form a valid identifier or
         number. If the characters form a number it is assumed to be the
         ORD value described in the previous paragraph, and if the
         characters form an identifier that is one of the enumerated type's
         constant identifiers, its value is assigned to P. In addition, if
         the variable is BOOLEAN, reading one of the digits 1 or 0 causes
         either true or false to be assigned to the BOOLEAN variable.
         'TRUE' and 'FALSE' are  also accepted as the BOOLEAN constant
         identifiers.

         The actual value of N is ignored: using the N notation
         directs the compiler to save the enumerated type's constant
         identifiers and make them available to the applicable READ routine.
         Omitting the N notation saves memory that would be used for the
         identifiers.

     4.  Reference types

         At the extend level, if P is a pointer type, a number is read as a
         WORD and assigned to P, in a way that depends on your
         implementation, so that writing a pointer and later reading it
         yields the same pointer value.  The address types should be read as
         WORDs using (.R) or (.S) notation.

     5.  String types

         At the extend level, if P is a STRING (n), then the next "n"
         characters are read sequentially into P. Preceding line markers,
         spaces, tabs, or form feeds are not skipped. If the line marker is
         encountered before n characters have been read, the remaining
         characters in P are set to blanks and the file position remains at
         the line marker.

         If the STRING is filled with n characters before the line
         marker is encountered, the file position remains at the next
         character. In a few implementations there may be a limit of 255
         characters on the length of a STRING read. P can be the super
         array type STRING (e.g., a reference parameter or pointer referent
         variable).

         At the extend level, if P is an LSTRING (n), then the next
         "n" characters are read sequentially into P, and the length of the
         LSTRING is set to "n".  Preceding line markers, spaces, tabs, or
         form feeds are not skipped. If the line marker is encountered
         before "n" characters have been read, the length of the LSTRING is
         set to the number of characters read and the file position remains
         at the line marker.

         If the LSTRING is filled with "n" characters before the line
         marker is encountered, the file position remains at the next
         character. P can be the super array type LSTRING (e.g., a
         reference parameter or pointer referent variable). READ (LSTRING)
         is handy when reading entire lines from a textfile, especially when
         the length of the line is needed. For example, the easiest way to
         copy a textfile is by using READLN and WRITELN with an LSTRING
         variable.

         Currently, READ and READLN do not use M field width
         parameters: you cannot read the line '123456' as two INTEGER
         numbers with READ (I:3, J:3). However, you can read two
         LSTRING (3) items and then decode them to achieve the same effect.


 16.2.3  WRITE and WRITELN


 PROCEDURE WRITE
 PROCEDURE WRITELN

       File system intrinsic procedures for textfile I/O. WRITE and
       WRITELN write textfiles. Both are defined in terms of the more
       primitive operation, PUT; that is, if P is an expression of type CHAR
       and F is a file of type TEXT, then WRITE (F, P) is equivalent to:

           BEGIN
             F^ := P;
             {Assign P to buffer variable F^.}
             PUT (F)
             {Assign F^ to next component of file.}
           END

       WRITE can take more than one parameter, as in
       WRITE (F, P1, P2,... Pn).  This is equivalent to the following:

           BEGIN
              WRITE (F, P1);
              WRITE (F, P2);
                .
                .
              WRITE (F, Pn)
           END

       The procedure WRITELN writes a line marker to the end of a
       line.  In all other respects, WRITELN is analogous to WRITE.  Thus,
       WRITELN (F, P1, P2, ... Pn) is equivalent to:

           BEGIN
              WRITE (F, P1, P2, ... Pn);
              WRITELN (F)
           END

       If either WRITE or WRITELN has no file parameter, the default
       file parameter is OUTPUT.  Therefore, the first statement in each of
       the following pairs is equivalent to the second:

           WRITE (P1, P2, ... Pn)
           WRITE (OUTPUT, P1, P2, ... Pn)

           WRITELN (P1, P2, ... Pn)
           WRITELN (OUTPUT, P1, P2, ... Pn)

       At the standard level, parameters in a WRITE can be expressions
       of any of the following types:

           CHAR

           INTEGER

           REAL

           BOOLEAN

           STRING

       At the extend level, expressions can also be of the following types:

           WORD

           INTEGER4

           LSTRING

           an enumerated type

           a pointer type

       Parameters may take optional M and N values (see Section 16.2.4,
       "WRITE Formats," for information about M and N parameters).

       Although the procedure WRITE can also write to a BINARY file
       (i.e., not a textfile), this is not recommended for DIRECT files
       after a SEEK operation, because the complementary READ form does not
       work as you might expect.

       For BINARY files, WRITE (F, X) is equivalent to:

           BEGIN
             F^ := X;
             PUT (F)
           END

       The form WRITE (F, P1, P2, ... Pn) is also acceptable. Normally,
       BINARY writes do not accept M and N values.


 16.2.4  WRITE Formats


 In textfiles, data parameters to WRITE and WRITELN may take on
 of the following forms:

      P   P:M   P:M:N   P::N


 The M and N values can be considered value parameters of type INTEGER
 and are used for formatting in various ways.  The extend level permits M
 and N values for both READs and WRITEs, and permits giving N without M, as
 in:

     P::N

 Using them in a nonstandard way is an error not caught at the
 standard level. In some cases only M, or N, or neither, is actually used;
 unused M and N values are ignored.

 Omitting M or N is the same as using the value MAXINT. For example,
 WRITE (12 : MAXINT) uses the default M value (8 in this case). Currently,
 M and N values are not accepted for BINARY files. In WRITE, the M value is
 the field width used as the number of characters to write. In
 ISO-Pascal, M must be greater than zero, and if the expression being
 written requires less than M characters, then it is padded on the left with
 spaces.

 At the extend level, M can also be negative or zero. If it is
 negative, the absolute value of M is used, but padding of spaces occurs on
 the right instead of the left. If it is zero, no characters are written.
 These are ISO standard errors not caught in MS-Pascal.

 If the representation of the expression cannot fit in ABS (M)
 character positions, then extra positions are used as needed for numeric
 types, or the value is truncated on the right for string types. If M is
 omitted or equal to MAXINT, a default value is used.

 The N value signifies:

     1.  the number of decimal places if P is of type REAL

     2.  the output radix if P is of type INTEGER, WORD, INTEGER4, or
         pointer

     3.  the numeric or identifier value if P is of an enumerated type

 Most of the following formatting rules apply to the function ENCODE as
 well.

     1.  INTEGER and WORD types

         If P is of type INTEGER, WORD, or a subrange thereof, then the
         decimal representation of P is written on the file. If P is a
         negative INTEGER, a leading minus sign is always written. WORD
         values are never negative. For INTEGER and WORD values, the default
         M value is 8.

         If ABS (M) is smaller than the representation of the number,
         additional character positions are used as needed. N is used to
         write in hexadecimal, decimal, octal, binary, or other base
         numbering using N equal to a number from 2 to 36; this is an
         extension to the ISO standard. If N is not 10 (or omitted or
         MAXINT), then padding on the left is with zeros and not spaces.
         Omitting N or setting N to MAXINT or 10 implies a decimal radix.

         WORD decimal numbers from 32768 to 65535 are written normally
         and not in their negative integer equivalents. All values written
         should be separated by spaces or some other character not valid in
         numbers, so that values are read as separate numbers.

     2.  REAL and INTEGER4 types

         If P is of type REAL, a decimal representation of the number P,
         rounded to the specified number of decimal places, is written on
         the file. If the N is missing or equal to MAXINT, a floating-point
         representation of P is written to the file, consisting of a
         coefficient and a scale factor. If N is included, a rounded
         fixed-point representation of P is written to the file, with N
         digits after the decimal point. If N is zero, P is written as a
         rounded integer, with a decimal point. The default value of M for
         REAL values is 14.

         Some examples of WRITE operations on REAL values:

             This Statement          Produces This Output
             
             WRITE (123.456)         ' 1.2345600E+02'
             WRITE (123.456:20)      ' 1.2345600000000E+02'
             WRITE (123.456::3)      '       123.456'
             WRITE (123.456:2:3)     ' 123.456'
             WRITE (123.456:-20:3)   '123.456             '

         At the extend level, if P is of type INTEGER4, the decimal
         representation of P is written on the file. The N value is used to
         set the radix, as in type INTEGER. The default M value is 14.

     3.  Enumerated and Boolean types

         At the extend level, if P is an enumerated type and N is omitted or
         equal to MAXINT then ORD (P) is written on the file, as if it were
         a WORD. If N is given with the value 1, the enumerated type's
         constant identifier for the value of P is written on the file, as
         if it were a STRING. Note that using this N notation causes memory
         to be allocated for the enumerated type's constant identifiers.

         At the standard level, if P is of type BOOLEAN, then one of
         the strings 'TRUE' or 'FALSE' is written to the file as a STRING.
         The ORD value is never written for BOOLEAN types as it is for
         enumerated types (although you can use WRITE(ORD(P)) instead).

     4.  Reference types

         At the extend level, if P is a pointer type, then P is written as a
         WORD. This is done in an implementation defined way such that
         writing a pointer and later reading it produces the same pointer
         value.  The address types should be written as WORD values using
         (.R) or (.S) notation.

     5.  String types

         If P is of type STRING (n), then the value of P is written on the
         file. The default value of M is the length of the STRING, "n".  If
         ABS (M) is less than the length of the string, then only the first
         ABS (M) characters are written. If M is zero, nothing is written.
         The right portion of the STRING is always truncated, even if M is
         negative.  In a few implementations, there may be a limit of 255
         characters on the length of a STRING write.

         At the extend level, if P is of type LSTRING (n), then the
         value of P is written on the file. The default value of M is the
         current length of the string, P.LEN. If ABS (M) is less than
         the current length, then only the first ABS (M) characters are
         written. If M is zero, then nothing is written. The right portion
         of the LSTRING is always truncated, even if M is negative. If
         ABS (M) is greater than the current length, spaces, not characters,
         fill the remaining positions past the length in the LSTRING. Note
         that a string of M blanks can be written with NULL : M.


 16.3  Extend Level I/O


 At the extend level, MS-Pascal has these additional I/O features:

     1.  You can access three FCB fields: F.MODE, F.TRAP, and F.ERRS.

     2.  A number of additional procedures are predeclared.

     3.  Temporary files are available.

 Section 8.6, "File I/O: Extend Level," discusses FCB fields in the
 context of files.  The additional procedures and temporary files are
 described in the following sections.


 16.3.1  Extend Level Procedures


 PROCEDURE ASSIGN (VAR F; CONSTS N : STRING);

       A file system procedure for extend level I/O. Assigns an operating
       system filename in a STRING (or LSTRING) to a file F. The filename
       format depends on the target operating system. As a rule, ASSIGN
       truncates any trailing blanks.  ASSIGN overrides any filename set
       previously. A filename must be set before the first RESET or REWRITE
       on a file. ASSIGN on an open file (after RESET or REWRITE but before
       CLOSE) produces an error. ASSIGN to INPUT or OUTPUT is allowed, but
       since these two files are opened automatically, they must be closed
       before being assigned to.


 PROCEDURE CLOSE (VAR F);

       A file system procedure for extend level I/O. Performs an operating
       system close on a file, ensuring that the file access is terminated
       correctly. This is especially important for file variables allocated
       on the stack or the heap. Since these files must be closed before a
       RETURN or DISPOSE loses the file control block, they are closed
       automatically when a RETURN or DISPOSE releases stack or
       heap file variables.

       File variables with the STATIC attribute in procedures and
       functions are also closed automatically when the procedure or
       function returns. Files allocated statically at the program, module,
       or implementation level are automatically closed when the entire
       program terminates.

       If necessary, when a CLOSE is executed, a file being written to
       has its operating system buffers flushed. However, the MS-Pascal
       buffer variable is not PUT. If a file of type TEXT is being written
       and the last nonempty line does not end with a line marker, one is
       added to the end of the last line. If the file has the mode
       SEQUENTIAL and is being written, an end-of-file is written.

       Note that some runtime errors may remove control from the MS-
       Pascal runtime system. In these cases, files being written may not
       be closed, and the information in them may be lost. A CLOSE on a
       file that is already closed or never opened (no RESET or REWRITE) is
       permitted. CLOSE is not ignored if error trapping is on and there
       was a previous error. CLOSE turns off error trapping for the file,
       and clears the error status if no errors were found.


 PROCEDURE DISCARD (VAR F);

       A file system procedure for extend level I/O. Closes and deletes an
       open file. DISCARD is much like CLOSE except that the file is
       deleted.


 PROCEDURE READFN (VAR F ; P1, P2, ... CR);

       A file system procedure for extend level I/O.  READFN is the
       same as READ (not READLN) with two exceptions:

       1.  File parameter F should be present (INPUT is assumed, but a
           warning is given if F is omitted).

       2.  If a parameter P is of type FILE, a sequence of characters
           forming a valid filename is read from F and assigned to P in
           the same manner as ASSIGN.

       Parameters of other types are read in the same way as the READ
       procedure.

       Note that READFN is like READ, not like READLN, and does not
       read the trailing line marker. If the first parameter in a READFN
       call is a file of any type, it is assumed to be the textfile from
       which characters are read. It is not assumed that the file's name
       should be read using INPUT as the default source.

       READFN is used internally to read a program's parameters. It is
       useful when reading a filename and assigning the filename to some
       file in one operation.


 PROCEDURE READSET
 (VAR F; VAR L : LSTRING, CONST S : SETOFCHAR);

       A file system procedure for extend level I/O. READSET reads
       characters and puts them into L, as long as the characters are in the
       set S and there is room in L. If no file parameter is given, INPUT
       is assumed, as in READ and WRITE. Leading spaces, tabs, form feeds,
       and line markers are always skipped.

       Reading ceases at the first line marker, which is never in the
       type CHAR.

       READSET, along with ENCODE, is used by the runtime system to do
       the formatted READ procedures, as well as to read filenames with
       READFN. It is handy when reading and parsing input lines for simple
       command scanners.

       In a segmented memory environment, the L and S parameters must
       reside in the default data segment.


 PROCEDURE SEEK (VAR F; N : INTEGER4);

       A file system procedure for extend level I/O. In contrast to normal
       sequential files, DIRECT files are random access structures. SEEK is
       used to randomly access components of such files. To use a DIRECT
       file, the MODE field must be set to DIRECT before the file is opened
       with RESET or REWRITE; the file, F, must be a DIRECT mode file.

       If the file is actually read or written sequentially, the usual
       READ and WRITE procedures can be used.

       SEEK modifies a field in file F so that the next GET or PUT
       applies to record number N. The record number parameter N can be of
       type INTEGER or WORD, as well as of type INTEGER4. For textfiles
       (ASCII structure), records are lines; for other files (BINARY
       structure), records are components. Record numbers start at one (not
       zero). If F is an ASCII file, SEEK sets the lazy evaluation status
       "empty." If F is a BINARY file, SEEK waits for I/O to finish and sets
       the concurrent I/O status "ready."

       SEEK is best illustrated by some examples. Assume for instance,
       that a BINARY structured, DIRECT mode file contains the following
       CHAR contents:

           +---+---+---+---+---+---+---+---+
           |'A'|'B'|'C'|'D'|'E'|'F'|'G'|   |
           +---+---+---+---+---+---+---+---+
        N =  1   2   3   4   5   6   7   8

       An implicit SEEK 1 is done after a REWRITE or a RESET.  Thus, with
       DIRECT mode files, the following sequences of commands might be
       given:

           RESET (F);
           {Initial SEEK 1, followed by GET;}
           {F^ now holds 'A'.}
           SEEK (F, 5);
           {File position set to 5; F^ still holds 'A'.}
           C := F^
           {C is now equal to 'A'; C does not equal 'E'.}

       Note that the fifth component is not assigned to C, as you
       might expect. To obtain this value, the following sequences of
       commands should be executed:

           RESET (F);
           {Initial SEEK 1, followed by GET;}
           {F^ now holds 'A'.}
           SEEK (F, 5);
           {File positioned at 5.}
           GET (F);
           {File buffer variable is loaded with 'E'.}
           C := F^
           {C gets value 'E'.}

       The rule to follow is to always follow a SEEK (F, N) with a GET to
       assure that the nth component is contained in the buffer variable.

       GET and PUT operate normally on DIRECT mode files with BINARY
       structured files. However, READ and WRITE work only with ASCII
       files, i.e., textfiles. READ, in particular, will not work with
       DIRECT mode BINARY files, because it assigns the buffer variable's
       value before it performs a GET. On the other hand, GET and PUT are
       not normally used with ASCII structured DIRECT mode files. Lazy
       evaluation makes READ and WRITE more appropriate. Care should always
       be taken when mixing normal sequential operations with DIRECT mode
       SEEK operations.


 16.3.2  Temporary Files


 Sometimes a program needs a "scratch" file for temporary, intermediate
 data.  If this is the case, you may create a temporary file that is
 independent of the operating system. To do so, without having to give the
 file a name in a specific format, ASSIGN a zero character as the name
 of the file. For example:

     ASSIGN (F, CHR (0))


 The file system creates a unique name for the file when it sees that
 the zero character has been assigned as a name.

 In environments where several running jobs are sharing a file
 directory, the job number is usually part of the name. Temporary files are
 deleted when they are closed, either explicitly or when the file gets
 deallocated. RESET and REWRITE do not delete the file.



 Chapter 17  Compilable Parts of a Program

 

 17.1  Programs

 17.2  Modules

 17.3  Units

        17.3.1  The Interface Division

        17.3.2  The Implementation Division



 The Microsoft Pascal Compiler can compile three kinds of source files:
 programs, modules, and implementations of units. Modules and
 implementations of units can be compiled separately and later be linked to
 a program without recompilation. At the standard level, you may compile
 only entire programs; modules and units are MS-Pascal features available at
 the extend level.

 Example of a compilable program:

      PROGRAM MAIN (INPUT, OUTPUT);
      BEGIN
        WRITELN ('Main Program')
      END. {Main}

 Example of a compilable module:

      MODULE MOD_DEMO;
      {No parameter list in heading}
        PROCEDURE MOD_PROC;
        BEGIN
          WRITELN
            ('Output from MOD_PROC in MOD_DEMO.')
        END
      END. {Mod_Demo}

 Example of a compilable unit:

      INTERFACE;
        UNIT UNIT_DEMO (UNIT_PROC);
        {UNIT_PROC is the only exported identifier.}
        PROCEDURE UNIT_PROC
      END
      IMPLEMENTATION OF UNIT_DEMO;
        PROCEDURE UNIT_PROC
        BEGIN
          WRITELN
            ('Output from UNIT_PROC in UNIT_DEMO.')
        END
      END. {Unit_Demo}

 If you compile MODULE MOD_DEMO and UNIT UNIT_DEMO separately, you can
 later incorporate them into the main program as shown below:

      {INTERFACE required at the start of any}
      {source that implements or uses a unit.}

      INTERFACE;
        UNIT UNIT_DEMO (UNIT_PROC);
        PROCEDURE UNIT_PROC
      END;

      PROGRAM MAIN (INPUT, OUTPUT);
      {USES clause below needed to connect}
      {implementation and program.}
      USES UNIT_DEMO;

      {EXTERN declaration needed to connect}
      {module's procedure.}
      PROCEDURE MOD_PROC; EXTERN;
      BEGIN
        WRITELN ('Output from Main Program.');
        MOD_PROC;
        UNIT_PROC
      END. {End of main program.}

 When the program MAIN is compiled, the output consists of the following
 pieces:

     1.  output from Program MAIN

     2.  output from MOD_PROC declared in MOD_DEMO

     3.  output from UNIT_PROC declared in UNIT_DEMO

 The rules governing the construction and use of programs, modules, and
 units are discussed in the following sections:

     Section 17.1, "Programs"
     Section 17.2, "Modules"
     Section 17.3, "Units"


 17.1  Programs


 Except for its heading and the addition of a period at the end, a
 Pascal program has the same format as a procedure declaration. The
 statements between the keywords BEGIN and END are called the body of the
 program.

 Example of a program:

      {Program heading}
      PROGRAM ALPHA (INPUT, OUTPUT, A_FILE, PARAMETER);

      {Declaration section}
      VAR A_FILE : TEXT;  PARAMETER : STRING (10);

      {Program body}
      BEGIN
        REWRITE (A_FILE);
        WRITELN (A_FILE, PARAMETER)
      END.
      {Ends with period (.)}

 The word "ALPHA" following the reserved word "PROGRAM" is the program
 identifier. The program identifier becomes the identifier for a
 parameterless PUBLIC procedure, at a scope above all other identifiers in
 the program. This procedure also has the PUBLIC identifier ENTGQQ,
 which is called during initialization to start program execution.

 You could call the program body as a PUBLIC procedure from another
 program, or from a module or unit, using the program identifier or ENTGQQ
 as the procedure name (but doing so is not recommended). This means that
 you can redeclare the program identifier within a program, and the usual
 scoping rules apply. The program identifier is at the same level as the
 predeclared identifiers, so giving a program an identifier like INTEGER or
 READ generates an error message.

 The program parameters denote variables that are set from outside the
 program. The program communicates with its environment through these
 variables.

 At the standard level, all variables of any FILE type should be
 present as program parameters, since there is no other way to give an
 operating system filename to the file. However, at the extend level,
 you may use the ASSIGN and READFN procedures to assign filenames, so
 file variables need not appear as program parameters.

 Program parameters differ entirely from procedure parameters; they
 are not passed as parameters to the procedure that is the body of the
 program. All program parameters must be declared in the variable
 declaration part of the block constituting the program. If there are no
 program parameters and the files INPUT and OUTPUT are not referenced, use
 the following form instead:

      PROGRAM identifier

 The two standard files INPUT and OUTPUT receive special treatment as
 program parameters. Their values are not set like other program
 parameters and should not be declared, since they are already predeclared.
 Each should be present as a program parameter if used either explicitly or
 implicitly in the program:

      WRITE (OUTPUT, 'Prompt:');   {Explicit use}
      READLN (INPUT, P);

      WRITE ('Prompt:')            {Implicit use}
      READLN (P);

 The compiler gives a warning if you use them in the program but omit
 them as program parameters. The only effect of INPUT and OUTPUT as program
 parameters is to suppress this warning.

 You may redefine the identifiers INPUT and OUTPUT. However, all
 textfile input and output procedures and functions (READ, EOLN, etc.) still
 use the original definition. RESET (INPUT) and REWRITE (OUTPUT) are
 generated automatically, whether or not they are present as program
 parameters; you may also generate them explicitly.

 Program initialization gives a value to every program parameter
 variable, except INPUT and OUTPUT. Each parameter must be either of a
 simple type or of a STRING, LSTRING, or FILE type (i.e., any type accepted
 by the READFN procedure). Program parameters must be entire variables: No
 component selection is permitted.

 Internally, each program parameter uses the file INPUT and generates
 READFN calls. Before each parameter is read, a special call is made to the
 internal routine PPMFQQ. PPMFQQ gets characters returned from an operating
 system interface routine called PPMUQQ, which gets them from the command
 line. PPMFQQ then effectively puts those characters at the start of the
 file INPUT. The identifier of the parameter is passed to both routines
 (PPMFQQ and PPMUQQ). Some operating systems then use the identifier as a
 prompt.

 The use of program parameters in MS-Pascal can best be illustrated by
 showing how to change a program into a procedure. Suppose you have a
 program like the following:

      PROGRAM ALPHA (INPUT, OUTPUT, P1, P2, ... Pn);
      declarations
      {Including those for P1, P2, ... Pn}
      BEGIN
        body
      END.

 PROGRAM ALPHA could then become the following procedure:

      PROCEDURE ENTGQQ [PUBLIC];
      declarations
      {Including those for P1, P2, ... Pn}
      BEGIN
        PPMFQQ ('P1'); READFN (INPUT, P1);
        PPMFQQ ('P2'); READFN (INPUT, P2);
        .
        .
        PPMFQQ ('Pn'); READFN (INPUT, Pn);
        PPMEQQ
        {Called after all parameters are read}
        program statements
      END;

 The action of the interface routine PPMFQQ depends on the target
 operating system. See your Microsoft Pascal Compiler User's Guide for
 more information on PPMFQQ and ENTGQQ.

 Some operating systems have elaborate mechanisms to handle this kind
 of parameter, using menus and default values. If your system falls into
 this category, the same mechanism generally applies to MS-Pascal program
 parameters.

 Other less sophisticated operating systems pass to a program the
 remainder of the command line that invoked it; in this case, parameter
 values are read from the command line.

 If the operating system does not provide a program parameter
 mechanism, or if an error occurs while using such a mechanism, or if it
 does not supply enough parameter values, then the PPMFQQ routine reverts to
 handling parameter values itself. It prompts you for every parameter with
 the parameter's identifier and reads the value you give it for the
 parameter. See Appendix B, "Version Specifics," in your Microsoft Pascal
 Compiler User's Guide for details on how your implementation initializes
 program parameters.


 17.2  Modules


 Modules provide a simple, straightforward method for combining several
 compilable segments into one program. Units, described in Section 17.3,
 "Units," provide a more powerful and structured method for achieving the
 same end.

 Basically, a module is a program without a body. The identifier in
 the module heading has the same scope as a program identifier. The heading
 can also include attributes that apply to all procedures and functions in
 the module. There are no module parameters; nor is there a module body. A
 module ends with the reserved word END and a period.

 Example of a module:

      MODULE BETA [PUBLIC]; {Optional attributes}

      PROCEDURE GAMMA;
         BEGIN WRITELN ('Gamma') END;

      FUNCTION DELTA : WORD;
         BEGIN DELTA := 123 END;

      END. {No body before END}

 After the module identifier, you may give one or more attributes (in
 brackets) to apply to all of the procedures and functions nested directly
 in the module. Depending on which, if any, attributes you specify, the
 following assumptions or restrictions apply:

     1.  If there is no attribute list at all, the PUBLIC attribute is
         assumed. However, if a list is present but empty, PUBLIC is not
         assumed.

     2.  The EXTERN directive used with a particular procedure or function
         overrides the PUBLIC attribute given (or assumed) for the entire
         module.

     3.  EXTERN and ORIGIN cannot be given as attributes for an entire
         module, although you may specify them for individual procedures and
         functions.

     4.  If PURE or INTERRUPT are used, the module must contain only
         functions for PURE and procedures for INTERRUPT.

     5.  PUBLIC is the default attribute for all procedures and functions.
         However, in some cases, a PUBLIC procedure call has more overhead
         than a purely local one. In other cases, the identifier of a local
         procedure may conflict with a global identifier passed to the
         linker. To avoid these problems, use PUBLIC with selected
         individual procedures and functions and empty brackets for the
         entire module (e.g., MODULE BETA [];).

 Although a module contains no body, only declarations, you may use it
 as a parameterless procedure; that is, you may declare the module
 identifier as a procedure and call it from other programs, modules, or
 units. This module procedure (unlike a similar procedure for programs or
 units) is never called automatically, since there is no way for the
 compiler to know whether a module has been loaded and thus whether to
 generate a call to it.

 However, in some cases, the compiler generates module initialization
 code that should be executed by calling the module as an EXTERN procedure.
 If such code is necessary, the compiler gives the warning:

      Initialize Module

 If you see this message, declare the module as a parameterless EXTERN
 procedure and call the procedure once before anything in the module is
 accessed. (You will need to do this if the module declares any FILE
 variables.)

 Given a module M that declares its own file variables, a program that
 uses M should look like this:

      PROGRAM P (INPUT, OUTPUT)
        .
        .
      PROCEDURE M; EXTERN;
      BEGIN
        M; {Runtime call initializes}
        .  {file variables.}
        .
      END.

 If the module USES any interfaces that require initialization, the
 compiler generates a warning that you should declare the module EXTERN and
 call it as described in the previous paragraph.

 If module M does not contain any of its own file variables or use any
 initialized units, there is no need to invoke M as a procedure in the body
 of the program or to declare it as an EXTERN procedure.

 Variables within modules are not automatically given any attributes.
 Except for the initialization of FILE variables mentioned above, variables
 within modules are the same as program variables.


 17.3  Units


 MS-Pascal units provide a structured way to access separately
 compiled modules. A unit has two parts:

     1.  an interface

     2.  an implementation

 The interface appears at the front of an implementation of a unit and
 at the front of any program, module, interface, or implementation, that
 uses a unit.

 A unit contains constants, types, super types, variables, procedures,
 and functions, all of which are declared in the interface of the unit. Any
 program, module, implementation, or another interface may use an interface.
 An implementation contains the bodies of the procedures and functions in a
 unit, as well as optional initialization for the unit. The general scheme
 is shown in Figure 17.1.


      +---------------------------------------------+
      |           INTERFACE; UNIT X;                |
      |           identifier-declarations           |
      |           END;                              |
      +-------------------+--+----------------------+
      | heading           |  | IMPLEMENTATION OF X; |
      | USES X;           |  | identifier-          |
      | declarations      |  |  implementations     |
      | optional-body     |  | optional-body        |
      | END.              |  | END.                 |
      +-------------------+  +----------------------+

            Figure 17.1. A Microsoft Pascal Unit


 When you are using units, their interfaces go before everything else in a
 source file, either in an IMPLEMENTATION or in the program, module, or
 other unit that uses it. In the preceding diagram, the INTERFACE is
 shared; the same INTERFACE exists in both the IMPLEMENTATION source file
 and in the other source file. Conversely, any other program, module, or
 unit could USE UNIT X; similarly, there could be another IMPLEMENTATION OF
 X, in assembly language, for example.

 By separating the interface from the implementation, you can write
 and compile a program before or while writing the implementation. Or, you
 may load a program with one of several implementations (for example, one in
 MS-Pascal or one in assembly language). A large MS-Pascal program is often
 better organized as a main program and a number of units (parts of the MS-
 Pascal runtime system are organized in this way). However, only a program,
 module, interface, or implementation can USE a unit, not an individual
 procedure or function.

 A program, module, implementation, or interface that uses an interface
 must start with the source file for that interface. Generally, the
 interface source file is a separate file, and an $include metacommand
 at the start of the source file brings in the interface source itself at
 compile time. Because there is then only one master copy of the interface,
 this is easier and more reliable than physically inserting the interface
 everywhere it is used (and running the risk of ending up with several
 different versions).

 In some applications, you may want several versions of the same
 interface. For example, there is a separate version of the MS-Pascal file
 control block interface for every target file system; the $included file is
 copied from the desired interface version before the program using it is
 compiled. Naturally, every version must declare the common identifiers;
 each might also have some constant values for use in $if metacommands for
 the version-specific portions of the interface.

 Suppose the INTERFACE for UNIT X in Figure 17.1 is contained in the
 file X.INT. If that is so, the compiland using the unit and the
 IMPLEMENTATION of the unit need only to $include the interface file at the
 start of the source file, as shown in Figure 17.2.


      +---------------------------------------------+
      |          {$INCLUDE:'X.INT'}                 |
      +--------------------+--+---------------------+
      | compiland-heading  |  | IMPLEMENTATION OF X;|
      | USES X;            |  | identifier-         |
      | declarations       |  |  implementations    |
      | optional-body      |  | optional-body       |
      | END.               |  | END.                |
      +--------------------+  +---------------------+

             Figure 17.2. Unit With File X.INT


 An MS-Pascal source file of any kind contains zero or more unit interfaces,
 separated by semicolons, and followed by a program, a module, or an
 implementation, which is followed by a period. Each of these entities is
 called a "division." See Section 17.3.1, "The Interface Division," and
 Section 17.3.2, "The Implementation Division," for details about divisions.

 A unit consists of the unit identifier, followed by a list of identifiers
 in parentheses. These identifiers are called the constituents of the
 unit and are the ones provided by a unit or required by a program,
 module, or other unit. The unit is preceded by the keyword UNIT for a
 provided unit or USES for a required one.

 All unit identifiers in a source file must be unique. The
 identifiers in parentheses, however, may differ in the providing and
 requiring divisions. Correspondence between identifiers provided and
 required is by position in the list (similar to formal and actual
 parameters in procedures).

 The identifier list in a USES clause is optional; if not given, the
 identifiers in the UNIT list are used by default. Giving different
 identifiers in a USES clause allows you to change the identifiers in case
 several different interfaces have identifier conflicts. Multiple USES
 clauses can be combined; thus, the following statements are equivalent:

      USES A; USES B; USES C;
      USES A, B, C;

 Note also that a unit may introduce optional initialization code.
 Such code is implied by the words BEGIN and END at the end of an
 interface and is provided in an optional body in an IMPLEMENTATION.

 Example of a unit that introduces initialization code:

 The program file, PLOTBOX:

      {$include:'GRAPHI'}
      PROGRAM PLOTBOX (INPUT, OUTPUT);
        USES GRAPHICS (MOVE, PLOT);
        {MOVE and PLOT are USEd identifiers.}
        BEGIN
          MOVE (0, 0);
          PLOT (10, 0); PLOT (10, 10);
          PLOT (0, 10); PLOT (0, 0)
        END.

 The interface file, GRAPHI:

      INTERFACE;
        UNIT GRAPHICS (BJUMP, WJUMP);
        {Exported identifiers are BJUMP and WJUMP.}
        {In the above PROGRAM, MOVE and PLOT}
        {are aliases for these identifiers.}
        PROCEDURE BJUMP (X, Y : INTEGER);
        PROCEDURE WJUMP (X, Y : INTEGER);
        {Procedure headings only above.}
      BEGIN
      {BEGIN implies initialization code.}
      END;

 The implementation file:

      {$include:'GRAPHI'}
      {$include:'BASEPL'}
      {The following implementation USES}
      {the UNIT BASEPL. Thus, the interface}
      {is included above and the unit}
      {used below.}
      IMPLEMENTATION OF GRAPHICS;
      {Implementation is invisible to user.}
        USES BASEPLOT;
         {Procedures BJUMP and WJUMP are}
         {implemented below.}
         {Note that only the identifiers}
         {are given in the heading.}
         {The parameter lists are given}
         {in the interface.}
        PROCEDURE BJUMP;
          BEGIN DRAWLINE (BLACK, X, Y) END;
        PROCEDURE WJUMP;
          BEGIN DRAWLINE (WHITE, X, Y) END;
      BEGIN
      {Begin initialization.}
        DRAWLINE (BLACK, 0, 0)
      END.

 The interface file, BASEPL:

      INTERFACE;
        UNIT BASEPLOT (BLACK, WHITE, DRAWLINE);
         {Other identifiers besides procedure}
         {identifiers can be exported.}
         {Note that BLACK and WHITE are}
         {exported constant identifiers.}
        TYPE RAINBOW = (BLACK, WHITE, RED, BLUE, GREEN);
        PROCEDURE DRAWLINE (C : RAINBOW; H,V : INTEGER);
      {No BEGIN; therefore, not an initialized unit.}
      END;

 A USES clause may occur only directly after a program, module,
 interface, or implementation heading. When the compiler encounters
 a USES clause, it enters each constituent identifier (from the UNIT
 clause or USES clause itself) in the symbol table. Identifiers for
 variables, procedures, and functions are associated with the
 corresponding identifiers in the interface, which then become external
 references for the linker.

 If the sample program above were compiled, every reference to the
 procedure PLOT would generate an external reference to WJUMP. However,
 references to DRAWLINE would use the same identifier for the external
 reference.

 Constants and types (including any super array types) in the
 interface are simply entered in the program's symbol table (along with the
 new identifier, if any). Thus, a type in an interface is identical to the
 corresponding type in the USES clause.

 Record field identifiers are the same in the program, interface, and
 implementation. Enumerated type constant identifiers must be given
 explicitly, if needed; they are not automatically implied by the enumerated
 type identifier. Labels cannot be provided by an interface, since the
 target label of a GOTO must occur in the same division as the GOTO.


 17.3.1  The Interface Division


 The structure of an interface is as follows:

     1.  An interface section starts with the reserved word INTERFACE, an
         optional version number in parentheses, and a semicolon.

     2.  Next comes the keyword UNIT, the unit identifier, the parenthesized
         list of exported (constituent) identifiers, and another semicolon.

     3.  Any other units required by this interface come next, in USES
         clauses.

     4.  The last section is the actual declarations for all identifiers
         given in the interface list, using the usual CONST, TYPE, and VAR
         sections and procedure and function headings, in any order.  No
         LABEL or VALUE sections are permitted.

     5.  The interface ends with BEGIN END if it has initialization, or just
         with END if  it has no initialization.

 Except for ORIGIN, which cannot currently be used in interfaces, most
 available attributes can be given to variables, procedures, and functions.
 Because the PUBLIC or EXTERN attribute or EXTERN directive is given
 automatically, you must not specify attributes that may conflict (e.g.,
 PUBLIC and EXTERN).

 Usually the only identifiers you declare are the constituents, but
 other identifiers are permitted. If the interface needs a call to
 initialize the unit, the keyword BEGIN generates the call. The
 interface ends with the reserved word END and a semicolon.

 Example of an interface division:

      INTERFACE (3);
        UNIT KEYFILE (FINDKEY, INSKEY, DELKEY, KEYREC);
          USES KEYPRIM (KFCB, KEYREC);

          PROCEDURE FINDKEY (CONST NAME : LSTRING;
              VAR KEY : KEYREC;
              VAR REC : LSTRING);
          PROCEDURE INSKEY  (CONST REC : LSTRING;
              VAR KEY : KEYREC);
          PROCEDURE DELKEY (CONST KEY : KEYREC);
          PROCEDURE NEWKEY (CONST KEY : KEYREC);
        BEGIN
        {Signifies initialized unit.}
        END;

 In this example, KEYREC is part of the unit KEYPRIM, but is exported
 as part of the unit KEYFILE. KFCB is also part of the KEYPRIM unit, but is
 not exported by the KEYFILE unit. NEWKEY is defined in the interface, but
 not exported by the KEYFILE unit. This is permitted, but pointless, since
 NEWKEY is unknown even in the the implementation of the unit.

 Memory available at compile time limits the number of identifiers the
 compiler can process. This limit can be a problem if you have many
 interfaces, especially interfaces that use other interfaces. The symptom
 is the following error message:

     Compiler Out Of Memory

 The message occurs before the final USES clause in the program,
 module, or implementation you are compiling. The cure is to reduce the
 number of identifiers in interfaces USEd by other interfaces. For example,
 make a single interface that contains only types (and type-related
 constants) shared by your other interfaces, and only USE this interface
 in the others.

 If you include any file variables in the interface, the unit must be
 initialized. The compiler does not give the usual warning,

      Initialize Variable

 when you declare a file in an interface. If your interface contains files,
 be sure to end it with BEGIN END so that it will be initialized.


 17.3.2  The Implementation Division


 You may compile an implementation of a unit separately from other
 programs, modules, or units, but you must compile it along with its
 interface.

 The structure of an implementation is as follows:

     1.  An implementation of an interface starts with the reserved words
         IMPLEMENTATION OF, followed by the unit identifier and a semicolon.

     2.  Next comes a USES clause for units it needs only for its own use.

     3.  Then comes the usual LABEL, CONSTANT, TYPE, VAR, and VALUE sections
         and all procedures and functions mentioned as constituents (which
         must be in the outer block) or used internally, in any order.

 VALUE and LABEL sections may appear in the implementation, but not in
 the interface.

 Example of an implementation:

      IMPLEMENTATION OF KEYFILE;
        USES KEYPRIM (KEYBLOCK, KEYREC);

        VAR KEYTEMP : KEYREC;

        PROCEDURE FINDKEY;
          BEGIN
            .
            {Code for FINDKEY}
            .
          END;

        PROCEDURE INKEY;
          BEGIN
            .
            {Code for INKEY}
            .
          END;

        PROCEDURE DELKEY;
          BEGIN
            .
            {Code for DELKEY}
            .
          END;

      BEGIN
        .
        {Any initialization code goes here.}
        .
      END.

 Constants, variables, and types declared in the interface are not
 redeclared in the implementation. However, you may declare other "private"
 ones. Procedures and functions that are constituents of the unit do not
 include their parameter list (it is implied by the interface) or any
 attributes. (The PUBLIC attribute is implied, unless the EXTERN directive
 is given explicitly.)

 All procedures and functions in the interface must be defined in the
 implementation. However, they can be given the EXTERN directive so that
 several implementations (or an implementation and assembly code) can
 implement a single interface. All procedures and functions with the EXTERN
 directive must appear first; the compiler checks for this and issues an
 error message if the EXTERN directive is missing or misplaced.

 You may implement a unit in assembly language, in which case all variables,
 procedures, and functions should generate public definitions for the
 loader. You may also implement units in other programming languages,
 such as MS-FORTRAN, or in a mixture of languages. If the interface is not
 implemented in MS-Pascal, it must give the proper calling sequence
 attribute (and of course you must be familiar with calling sequences and
 internal representation of parameters).

 Several MS-Pascal runtime units are implemented partially in MS-Pascal
 and partially in assembly language. As mentioned, any implementation
 section that does not implement all interface procedures and functions
 must, at the start of the implementation, declare such procedures and
 functions to be EXTERN.

 An implementation, like a program, may have a body. The body is
 executed when the program that uses the unit is invoked, so any
 initialization needed by the unit can be done. This includes internal
 initialization, such as file variable initialization, as well as user
 initialization code. If the source file contains several units, each
 implementation body is called in the order its USES clause appears in the
 source file. However, initialization code for a unit is executed only
 once, no matter how many clauses refer to it.

 The body, as in a program, is a list of statements enclosed with the
 reserved words BEGIN and END. At initialization time, the version number
 of the interface with which the implementation was compiled is compared
 against the version number of the interface with which the program was
 compiled. These must be the same. This checking prevents you from trying
 to run a program with obsolete implementations. If no version number is
 given, zero is assumed.

 The keyword BEGIN before the final END indicates a unit with
 initialization. If the word BEGIN is omitted, the implementation must
 not have a body and no initialization takes place. Uninitialized units
 lack the following:

     1.  user initialization code

     2.  a guarantee of only one initialization

     3.  a version number check

 The format for an initialized implementation of a unit is similar to a
 program:

      IMPLEMENTATION OF unit-identifier
      declarations
      BEGIN
         body   {Initialization code}
      END.

 The format for an uninitialized implementation of a unit is similar
 to a module:

      IMPLEMENTATION OF unit-identifier
      declarations
      {No initialization code}
      END.

 If the implementation for an uninitialized unit declares any files or
 USES any interfaces that require initialization, the compiler warns you to
 initialize the implementation. Initialization is done automatically if you
 add the keyword BEGIN to both the interface and the implementation. As
 with a module, you can declare an uninitialized unit to be a procedure with
 the EXTERN attribute and then initialize it by calling it from the program.



 Chapter 18  Microsoft Pascal Metacommands

 

 18.1  Language Level Setting and Optimization

 18.2  Debugging and Error Handling

 18.3  Source file control

 18.4  Listing File Control

 18.5  Listing File Format



 Metacommands make up the compiler control language. Metacommands are
 compiler directives that allow you to control such things as the following:

     1.  Microsoft Pascal language level

     2.  debugging and error handling

     3.  optimization level

     4.  use of the source file during compilation

     5.  listing file format

 You can specify one or more metacommands at the start of a comment;
 you should separate multiple metacommands with either spaces or commas.
 Spaces, tabs, and line markers between the elements of a metacommand
 are ignored. Thus, the following are equivalent:

      {$page:12}
      {$page : 12}

 To disable metacommands within comments, place any character that is
 not a tab or space in front of the first dollar sign, as shown:

      {x$page:12}

 You may change compiler directives during the course of a program;
 for example, most of a program might use $list-, with a few sections
 using $list+ as needed. Some metacommands, such as $linesize, normally
 apply to an entire compilation.

 If you are writing Microsoft Pascal programs for use with other
 compilers, keep in mind the fact that metacommands are always
 nonstandard and rarely transportable.

 Metacommands invoke or set the value of a metavariable.
 Metavariables are classified as typeless, integer, on/off switch, or
 string.

     1.  Typeless metavariables are invoked when used, as in $extend.

     2.  Integer metavariables can be set to a numeric value, as in
         $page:101.

     3.  On/off switches can be set to a numeric value so that a value
         greater than zero turns the switch on and a value equal or less
         than zero turns it off, as in $mathck:1.

     4.  String metavariables can be set to a character string value, such
         as with $title:'com program'.

 Table 18.1 illustrates the notational conventions observed in the
 metacommand descriptions that follow.


       Table 18.1
       Metacommand Notation
ķ
       Notation     Meaning
      
                    Metacommand is typeless.

       + or -       Metacommand is an on/off switch.
                    + sets value to 1 (on).
                    - sets value to 0 (off).
                    Default is indicated by + or - in heading.

       :<n>         Metacommand is an integer.

       :'<text>'    Metacommand is a string.

 String values in the metalanguage may be either a literal string or string
 constant identifier. Constant expressions are not allowed for either
 numbers or strings, although you can achieve the same effect by declaring a
 constant identifier equal to the expression and using the identifier in the
 metacommand.

 In metacommands only, Boolean and enumerated constants are changed to
 their ORD values. Thus, a Boolean false value becomes 0 and true becomes 1.

 A complete alphabetical listing of MS-Pascal metacommands is given in
 Appendix G, "Summary of Microsoft Pascal Metacommands."


 18.1  Language Level Setting and Optimization


 The metacommands shown in Table 18.2 let you control the level (standard,
 extend, or system) at which the compiler processes your program and
 the degree to which optimization is used. Some of these metacommands
 may not be implemented in your version of the compiler. See Appendix B,
 "Version Specifics," in your Microsoft Pascal Compiler User's Guide for
 details.


 Table 18.2
 Language and Optimization Level
ķ
 Name           Description
 
 $decmath       Directs the compiler to use the decimal
                math routines in the auxiliary decimal
                math runtime library.

 $extend        Adds extend level features

 $floatcalls    Directs the compiler to make calls to
                the real number math routines; set to
                $floatcalls+ by default

 $integer:<n>   Sets the length of the INTEGER type

 $real:<n>      Sets the length of the REAL type

 $rom           Gives a warning on static initialization

 $simple        Disables global optimizations
 Name           Description
$simple        Disables global optimizations

 $size          Minimizes size of code generated

 $speed         Minimizes execution time of code

 $standard      Enables standard level only

 $system        Adds extend and system level features

 The compiler issues a warning message if it encounters a feature whose
 level is not enabled. The default setting is $extend, which permits
 structured extensions that are relatively safe and portable. It also
 requires you to explicitly request $system extensions, which are by their
 nature low level, machine dependent, and relatively unstructured.

 $Integer and $real set the length (i.e., precision) of the standard
 INTEGER and real data types. $Integer takes an integer parameter, which
 must 2 or 4. However, you may set $real to either 4, or 8 (the default),
 to make type REAL identical to REAL4 or REAL8, respectively.

 The effect of the $size and $speed metacommands varies with the
 version of the optimizer in your implementation of the compiler. The
 default is $size. If you select $simple, no optimization of any kind is
 done. $Size, $speed, and $simple are all mutually exclusive.

 If $rom is set, the compiler gives a warning that static data will
 not be initialized in either of the following situations:

     1.  at a VALUE section

     2.  every place where static data initialization occurs due to $initck
         (described in Section 18.2, "Debugging and Error Handling")

 $Decmath+ directs the compiler to make calls to the decimal math support
 routines in which decimal floating-point numbers up to 14 digits and within
 a limited exponent range can be represented exactly. The results of the
 operations on the numbers in this format are also represented exactly if
 they are in the allowable range. If $decmath+ is used, it must precede any
 program text and may not be switched on and off.

 See your Microsoft Pascal Compiler User's Guide for any special
 instructions you must follow to use the decimal math package on your
 system.

 $Floatcalls+ generates calls to a real math runtime package to carry out
 floating-point operations. The $floatcalls- metacommand directs the
 compiler to generate in-line instruction "skeletons" for floating-point
 operations.


 18.2  Debugging and Error Handling


 The metacommands shown in Table 18.3 are for debugging and error
 handling. They also generate code to check for runtime errors.


 Table 18.3
 Debugging and Error Handling
ķ
 Metacommand    Description
 Metacommand    Description
 
 $brave+        Sends error messages and warnings to the
                terminal screen

 $debug-        Turns on or off all the debug checking
                (CK in metacommands below); off by
                default

 $entry-        Generates procedure entry/exit calls for
                debugger

 $errors:<n>    Sets number of errors allowed per page
                (default is 25)

 $goto-         Flags GOTO statements as "considered
                harmful"

 $indexck-      Checks for array index values in range,
                including super array indices; off by
                default
 Metacommand    Description
               default

 $initck-       Checks for use of uninitialized values;
                off by default

 $line-         Generates line number calls for the
                debugger

 $mathck-       Checks for mathematical errors such as
                overflow and division by zero; off by
                default

 $nilck-        Checks for bad pointer values; off by
                default

 $rangeck-      Checks for subrange validity; off by
                default

 $runtime-      Determines context of runtime errors

 Metacommand    Description

 $stackck-      Checks for stack overflow at procedure
                or function entry; off by default

 $tagck-        Checks tag fields in variant records;
                off by default.

 $warn+         Gives warning messages in listing file

 If any check is on when the compiler processes a statement, tests relevant
 to the statement are done. A runtime error invokes a call to the
 runtime support routine, EMSEQQ (synonymous with ABORT). When EMSEQQ is
 called, the compiler passes the following information to it:

     1.  an error message

     2.  a standard error code

     3.  an optional error status value, such as an operating system return
         code

 EMSEQQ also has available:

     1.  the program counter at the location of the error

     2.  the stack pointer at the location of the error

     3.  the frame pointer at the location of the error

     4.  the current line number (if $line is on)

     5.  the current procedure or function name and the source filename in
         which the procedure or function was compiled (if $entry is on)

 Each of these metacommands is discussed in more detail on the
 following pages. Most of the metacommands in this group may also be given
 as command line switches to the compiler. See Section 18.6, "Command Line
 Switches," for details.


 $brave+

     Sends error messages and warnings to your terminal (in addition to
     writing them to the listing file). If the number of errors and
     warnings is more than will fit on the screen, the earlier ones scroll
     off and you will have to check the listing file to see them all.


 $debug-

     Turns on or off all of the debug switches (i.e., those that end with
     "CK"). You may find it useful to use $debug- at the beginning of a
     program to turn all checking off and then selectively turn on only the
     debug switches you want. Alternatively, you may use this metacommand
     to turn all debugging on at the start and then selectively turn off
     those you don't need as the program progresses. By default, some error
     checks are on and some off.


 $entry-

     Generates procedure and function entry and exit calls. This lets a
     debugger or error handler determine the procedure or function in which
     an error has occurred. Since this switch generates a substantial
     amount of extra code for each procedure and function, you should use it
     only when debugging. Note that $line+ requires $entry+; thus, $line+
     turns on $entry, and $entry- turns off $line.


 $errors:n

     Sets an upper limit for the number of errors allowed per page.
     Compilation terminates if that number is exceeded. The default is 25
     errors and/or warnings per page.


 $goto-

     Flags GOTO statements with a warning that they are "considered
     harmful." This warning may be useful in either of the following
     circumstances:

     1.  to encourage structured programming in an educational environment

     2.  to flag all GOTO statements during the process of debugging


 $indexck-

     Checks that array index values, including super array indices, are in
     range. Since array indexing occurs so often, bounds checking is
     enabled separately from other subrange checking.


 $initck-

     Checks for the occurrence of uninitialized values, such as the
     following:

     1.  uninitialized INTEGERs and 2-byte INTEGER subranges with the
         hexadecimal value 16#8000

     2.  uninitialized 1-byte INTEGER subranges with the hexadecimal value
         16#80

     3.  uninitialized pointers with the value 1 (if $nilck is also on)

     4.  uninitialized REALs with a special value

     The $initck metacommand generates code to perform the following
     actions:

     1.  set such values uninitialized when they are allocated

     2.  set the value of INTEGER range FOR-loop control variables
         uninitialized when the loop terminates normally

     3.  set the value of a function that returns one of these types
         uninitialized when the function is entered

     $Initck never generates any initialization or checking for WORD or
     address types. Statically allocated variables are loaded with their
     initial values. Also, $initck does not check values in an array or
     record when the array or record itself is used.

     Variables allocated on the stack or in the heap are assigned initial
     values with generated code. $Initck does not initialize any of the
     following classes of variables:

     1.  variables mentioned in a VALUE section

     2.  variant fields in a record

     3.  components of a super array allocated with the NEW procedure


 $line-

     Generates a call to a debugger or error handler for each source line
     of executable code. This allows the debugger to determine the number
     of the line in which an error has occurred. Because this metacommand
     generates a substantial amount of extra code for each line in a
     program, you should turn it on only when debugging. Note that $line+
     requires $entry+, so $line+ turns on $entry, and $entry- turns off
     $line.


 $mathck-

     Checks for mathematical errors, including INTEGER and WORD overflow
     and division by zero. $Mathck does not check for an INTEGER result of
     exactly -MAXINT-1 (i.e., #8000); $initck does catch this value if it is
     assigned and later used.

     Turning $mathck off does not always disable overflow checking. There
     are, however, library routines that provide addition and multiplication
     functions that permit overflow (LADDOK, LMULOK, SADDOK, SMULOK, UADDOK,
     and UMULOK). See Section 15.2, "Directory of Functions and
     Procedures," for descriptions of each of these functions.


 $nilck-

     Checks for the following conditions:

     1.  dereferenced pointers whose values are NIL

     2.  uninitialized pointers if $initck is also on

     3.  pointers that are out of range

     4.  pointers that point to a free block in the heap

     $Nilck occurs whenever a pointer is dereferenced or passed to the
     DISPOSE procedure. $Nilck does not check operations on address types.


 $rangeck-

     Checks subrange validity in the following circumstances:

     1.  assignment to subrange variables

     2.  CASE statements without an OTHERWISE clause

     3.  actual parameters for the CHR, SUCC, and PRED functions

     4.  indices in PACK and UNPACK procedures

     5.  set and LSTRING assignments and value parameters

     6.  super array upper bounds passed to the NEW procedure


 $runtime-

     If the $runtime switch is on when a procedure or function is
     compiled, the "location of an error" is the place where the procedure
     or function was called rather than the location in the procedure or
     function itself. This information is normally sent to your terminal,
     but you could link in a custom version of EMSEQQ, the error message
     routine, to do something different (such as invoke the runtime debugger
     or reset a controller). For more information on error handling, see
     Chapter 10, "Advanced Topics," in your Microsoft Pascal Compiler
     User's Guide.


 $stackck-

     Checks for stack overflow when entering a procedure or function and
     when pushing parameters larger than four bytes on the stack. In some
     implementations, stack overflow is always checked. In some
     implementations, stack overflow is never checked in procedures with the
     INTERRUPT attribute.


 $tagck-

     Checks tag values when accessing a variant field. Only those tag
     fields with identifiers (i.e., whose value is actually stored in the
     record) are checked.


 $warn+

     Sends warning messages to the listing file (this is the default). If
     this switch is turned off, only fatal errors are printed in the source
     listing.


 18.3  Source file control


 A small group of metacommands provide some measure of control over the use
 of the source file during compilation. These commands are listed in Table
 18.4 and described in more detail below.


 Table 18.4
 Source File Control
ķ
 Name                  Description
 
 $if constant          Allows conditional compilation
   $then text1         of text1 source if constant
   $else text2         is greater than zero
 $end

 $include:'filename'   Switches compilation from
                       current source file to source
                       file named
 Name                  Description
                      file named

 $inconst:text         Allows interactive setting
                       of constant values at
                       compile time

 $message:'text'       Allows the display of a message
                       to the terminal screen to indicate
                       which version of a program is
                       compiling

 $pop                  Restores saved value of all
                       metacommands

 $push                 Saves current value of all
                       metacommands

 Because the compiler keeps one look-ahead symbol, it actually
 processes metacommands that follow a symbol before it processes the symbol
 itself. This characteristic of the compiler can be a factor in cases such
 as the following:

      CONST Q = 1;
      {$if q $then}
      {Q is undefined in the $if.}

      CONST Q = 1; DUMMY = 0;
      {$if q $then}
      {Now Q is defined.}
      X := P^;
      {$nilck+}
      {NILCK applies to P^ here.}

      X := P^;;;
      {NILCK doesn't apply to P.}
      {$nilck-}

 Each of these metacommands is discussed in more detail on the
 following pages.


 $if constant $then text $end

     Allows for conditional compilation of a source text. If the
     value of the constant is greater than zero, then source text following
     the $if is processed; otherwise it is not. an $if $then $else
     construction is also available, as in the following example:

         {$if msdos $then}
         SECTOR = S12;
         {$else}
         SECTOR  = S128;
         {$end}

     To simulate an "if not" construction, use the following form of the
     metacommand:


         $if constant $else text $end

     The constant may be a literal number or constant identifier. The
     text between $then, $else, and $end is arbitrary; it can include line
     breaks, comments, other metacommands (including nested $ifs), etc. Any
     metacommands within skipped text are ignored, except, of course,
     corresponding $else or $end metacommands.

     Examples using the metaconditional:

         {$if FPCHIP $then}
           CODEGEN (FADDCALL, T1, LEFTP)
         {$end}
         {$if COMPSYS $else}
           IF USERSYS THEN DO_IT_TO_IT
         {$end}


 $include

     Allows the compiler to switch processing from the current source to
     the file named. When the end of the file that was included is reached,
     the compiler switches back to the original source and continues
     compilation. Resumption of compilation in the original source file
     begins with the line of source text that follows the line in which the
     $include occurred. Therefore, the $include metacommand should always be
     last on a line.


 $inconst

     Allows you to enter the values of the constants (such as those used
     in $ifs) at compile time, rather than editing the source. This is
     useful when you use metaconditionals to compile a version of a source
     for a particular environment, customer, target processor, etc.
     Compilation may be either interactive or batch oriented. For example,
     the metacommand $inconst:year produces the following prompt for the
     constant YEAR:

         Inconst : YEAR =

     You need only give a response like:

         Inconst : YEAR = 1983

     The response is presumed to be of type WORD. The effect is to
     declare a constant identifier named YEAR with the value 1983. This
     interactive setting of the constant YEAR is equivalent to the constant
     declaration:


         CONST YEAR = 1983;

     You may also respond with a quoted string literal to create a
     constant of type STRING (n). For example, the source file metacommand
     $inconst:header prompts for a header. By enclosing a literal string
     constant in quotes, you declare a string constant:

         Inconst : HEADER = 'Processor Version 2.75'


 $message

     on
 Allows you to send messages to your terminal during compilation.
     This is particularly useful if you use metaconditionals extensively,
     for example, and need to know which version of a program is being
     compiled.

     Example of the $message metacommand:

         {$message:'Message on terminal screen!'}


 $push and $pop

     Allow you to create a meta-environment you can store with $push
     and invoke with $pop. $Push and $pop are useful in $include files for
     saving and restoring the metacommands in the main source file.


 18.4  Listing File Control


 The metacommands listed in Table 18.5 and described in this section
 allow you to format the listing file as you wish.


 Table 18.5
 Listing File Control Metacommands
ķ
 Metacommand           Description
 
 $linesize:n           Sets width of listing. Default
                       is 79 or 131, depending on
                       implementation.

 $list+                Turns on or off source listing.
                       Errors are always listed.

 $ocode+               Turns on disassembled object code
                       listing.

 $page+                Skips to next page. Line number
                       is not reset.

 $page:n               Sets page number for next page
                       (does not skip to next page).

 Metacommand           Description

 $pageif:n             Skips to next page if less than n
                       lines left on current page.

 $pagesize:n           Sets length of listing in lines.
                       Default is 55.

 $skip:n               Skips n lines or to end of page.

 $subtitle:'text'      Sets page subtitle.

 $symtab+              Sends symbol table to listing
                       file.

 $title:'text'         Sets page title.


 $linesize:n

     Sets the maximum length of lines in the listing file. This
     value normally defaults to either 131 or 79, depending on the
     implementation. See Appendix B, "Version Specifics," in your
     Microsoft Pascal Compiler User's Guide for the default on your
     system.


 $list+

     Turns on the source listing. Except for $list-, metacommands
     themselves appear in the listing. The format of the listing file is
     described in Section 18.5, "Listing File Format."


 $ocode+

     Turns on the symbolic listing of the generated code to the object
     listing file. Although the format varies with the target code
     generator, it generally looks like an assembly listing, with code
     addresses and operation mnemonics. In many cases, the identifiers for
     procedure, function, and static variables are truncated in the object
     listing file.


 $page+

     Forces a new page in the source listing. The page number of the
     listing file is automatically incremented.


 $page:n

     Sets the page number of the next page of the source listing. $page:n
     does not force a new page in the listing file.


 $pageif:n

     Conditionally performs $page+, if the current line number of the
     source file plus n is less than or equal to the current page size.


 $pagesize:n

     Sets the maximum size of a page in the source listing. The default is
     55 lines per page.


 $skip:n

     Skips n lines or to the end of the page in the source listing.


 $subtitle:'subtitle'

     Sets the name of a subtitle that appears beneath the title at the top
     of each page of the source listing.


 $symtab+

     If on at the end of a procedure, function, or compiland, sends
     information about its variables to the listing file (for example, see
     lines 14 and 17 in the sample listing file in Section 18.5, "Listing
     File Format"). The left columns contain the following:


     1.  the offset to the variable from the frame pointer (for variables in
         procedures and functions)

     2.  the offset to the variable in the fixed memory area (for main
         program and STATIC variables)

     3.  the length of the variable

     A leading plus or minus sign indicates a frame offset.  Note that this
     offset is to the lowest address used by the variable.

     The first line of the $symtab listing contains the offset to the
     return address, from the top of the frame (zero for the main program),
     and the length of the frame, from the framepointer to the end including
     front end temporary variables. Code generator temporary variables are
     not included.

     For functions, the second line contains the offset, length, and type
     of the value returned by the functions. The remaining lines list the
     variables, including their type and attribute keywords, as shown in the
     following list.

         Keyword   Meaning
         
         Public    Has the PUBLIC attribute

         Extern    Has the EXTERN attribute

         Origin    Has the ORIGIN attribute

         Static    Has the STATIC attribute

         Const     Has the READONLY attribute

         Value     Occurs in a VALUE section

         ValueP    Is a value parameter

         VarP      Is a VAR or CONST parameter

         VarsP     Is a VARS or CONSTS parameter

         ProcP     Is a procedural parameter

         Segmen    Uses segmented addressing

         Regist    Parameter passed in register


 $title:'title'

     Sets the name of a title that appears at the top of each page of the
     source listing.


 18.5  Listing File Format


 The following discussion of listing file format is keyed to this
 sample listing:

 Use   Title                                    PAGE   1
 User  Subtitle                                 12/11/82
                                                10:49:17
 JG IC Line#  Source Line   MS-Pascal Version 3.0  10/82
    00     1  PROGRAM foo;   {$symtab+}
    10     2  VAR i : integer; K : ARRAY [-9..0] OF integer,
           2  --------------------Warning 156,Assumed ;^
    20     3  FUNCTION bar (VAR j : integer) : integer;
    20     4    VAR k : ARRAY [0..9] OF integer;
    20     5    BEGIN
 +  21     6    GOTO 1;         {jump forward}
           6  -------^Warning 281 Label Assumed Declared
  = 21     7     i := bar (j);  {assign to global}
           8     1 :             {label}
  / 21     9     j := bar (i);  {global to VAR parm}
 -  21    10     GOTO 1;        {jump backward}
 *  21    11     RETURN; GOTO 1;{other jumps}
  % 21    12     i := bar (i);  {other global reference}
    21    13     j := bar (j);   {no global references}
    10    14    END;
          14  ----^306 Function Assignment Not Found

 Symtab   14  Offset Length Variable - BAR
              -    2     24 Return offset, Frame length
              -    2      2 (func'n return) : Integer
              +    4      2 J               : Integer VarP
              -   22     20 K               : Array

    10    15  BEGIN
    11    16   i := bar (i);
    00    17  END.

 Symtab   17  Offset Length Variable
                   0     24 Return offset, Frame length
                   2      2 I              : Integer
                   4     20 K              : Array

              Errors  Warns In Pass One
                   1      2

 Every page has a heading that includes such information as your title and
 subtitle, set with the metacommands $title and $subtitle,
 respectively. If these metacommands appear on the first source line,
 they take effect on the first page. The page number appears in the right
 side of the first line of the heading. In some versions, the date and time
 appear in the right side of the second and third line, respectively. You
 can set the page number with $page:n or start a new page with $page+.

 The fourth line of the listing contains the column labels. The
 contents of the first three columns are as follows:

     1.  The JG column

         The JG column contains flag characters generated for your
         information. Jump flags, which appear under the J, may contain one
         of the following characters:

         +    forward jump (BREAK or GOTO a label
              not yet encountered)

         -    backward jump (CYCLE or GOTO a label
              already encountered)

         *    other jumps (RETURN or a mixture of
              jumps)

         Codes for global variables (not local to the current procedure or
         function) appear in the column under G:

         =    assignment to a nonlocal variable

         /    passing a nonlocal variable as a
              reference parameter

         %    a combination of the two

     2.  The IC column

         The IC column contains information about the current nesting
         levels. The digit under the I refers to the identifier (scope)
         level, which changes with procedure and function declarations, as
         well as with record declarations and WITH statements. The digit in
         the C column refers to the control statement level; this number
         changes with BEGIN and END pairs, as well as with CASE and END and
         REPEAT and UNTIL pairs. The number in this column is useful for
         finding missing END keywords.

         If a line is not actively used by the compiler, all these columns
         are blank. Thus you can locate a portion of the source
         accidentally commented out or skipped due to an $if and $end pair.

     3.  The Line column

         The Line column shows the line number of the line in the
         source file. An $included file gets its own sequence of line
         numbers. If $line is on, this line number and the source file name
         identify runtime errors.

 Two kinds of compiler messages appear in the listing:  errors and
 warnings. A compilation with any errors cannot generate code. A compilation
 with warnings only can generate code, but the result may not execute
 correctly. Warnings start with the word "Warning" and a number (see, for
 example, line 2 in the sample listing). Errors start with an error number
 (see line 14 in the sample listing).

 You can suppress warning messages with the metacommand $warn-, but
 this is not generally recommended. The metacommand $brave+ sends
 error and warning messages to your terminal (as well as to the listing
 file). However, if there are more than will fit on a single screen, the
 first ones will scroll off.

 The location of the error is indicated in the listing file with an up
 arrow (^). The message itself may appear to the left or right of the arrow
 and is preceded with a dashed line.

 Sometimes, the compiler does not detect an error until after the
 listing of the following line. In this case, the error message line number
 is not in sequence. Tabs are allowed in the source and are passed on to
 the listing unchanged. If the tab spacing is every eight columns, the error
 pointer (^) is generally correct. However, an error pointer near the end of
 a line may be displaced if the following line has tabs.

 If the compiler encounters an error from which it cannot recover, it
 gives the message "Compiler Cannot Continue!". This message appears if any
 of the following occurs:

     1.  The keyword PROGRAM (or IMPLEMENTATION, INTERFACE, or MODULE) is
         not found, or the program, module, or unit identifier is missing.

     2.  The compiler encounters an unexpected end-of-file.

     3.  The compiler finds too many errors; the maximum number of errors
         per page is set with the $errors metacommand (the default is 25).

     4.  The identifier scope becomes too deeply nested. (See Appendix B,
         "Version Specifics," in your Microsoft Pascal Compiler User's Guide
         for the nesting level limit for your implementation.)

 When the compiler is unable to continue, for whatever reason, it simply
 writes the rest of the program to the listing file with very little
 error checking.



 Appendices

 

 A     Pascal Syntax Diagrams

 B     Microsoft Pascal Features and the ISO Standard

 C     Microsoft Pascal and Other Pascals

 D     ASCII Character Codes

 E     Summary of Microsoft Pascal Reserved Words

 F     Summary of Available Procedures and Functions

 G     Summary of Microsoft Pascal Metacommands



 Appendix A  Pascal Syntax Diagrams

 

 The diagrams on the following pages show the fundamental syntax of the
 Microsoft Pascal language. They are arranged in the order that you would be
 likely to use the elements while writing a program. The meaning of the
 differently shaped outlines is as follows:

     1.  Rectangles

         Indicate reserved words or symbols of the MS-Pascal language. These
         must be typed as shown.

     2.  Double-lined rectangles

         Indicate higher-level constructions that usually have syntax
         diagrams of their own.

     3.  High boxes with double lines at top and bottom

         Indicate punctuation that is required and must be typed as shown.

     4.  Arrows

         Help to show the path through the diagram, including any possible
         looping (i.e., repetition of syntax elements).


 Source File
                      Ŀ
         Ŀ    ͸     ͻ     ͸    ͸     Ŀ
 INTERFACE(number);UNITĿ
            ;     ͼ     ;     ;      
            
             ͻ     ͸     ͻ     ͸    ͸
            identifier(identifier);Ŀ
              ͼ     ;    ͼ    ;    ; 
                                          ͸                    
                                    Ĵ,             
                                           ;                     
      
                                    Ŀ
       ͻ    ͻ    Ŀ    Ŀ     ͸
      uselistdeclarationsBEGINEND;Ŀ
        ͼ     ͼ               ; 
    
                                     Ŀ
        ͻ      ͻ    ͸     ͻ     ͸ 
    PROGRAMidentifier(identifier)Ŀ
        ͼ      ͼ     ;    ͼ    ;   
                                                   ͸               
                                             Ĵ,        
                                                    ;                
        Ŀ     Ŀ     ͻ                     
    IMPLEMENTATIONOFidentifierĴ
                  ͼ                     
                                     Ŀ               
          Ŀ     ͻ    ͻ                  
    MODULEidentifierattributesĴ
                ͼ     ͼ                   
                                              ͸                       
    Ĵ;
                                            ;
                ͻ    ͻ
    uselistdeclarationsĿ
                 ͼ     ͼ                           
    
       Ŀ     ͻ    Ŀ     ͸
    BEGINstatementEND.
            ͼ         ;
                       ͸     
                 Ĵ;
                        ;


 Identifier
          ͻ
 letter
          ͼ                    ͻ   
                                   ĶletterĴ
                                      ͼ   
                                      ͻ    
                                   ĶdigitĴ
                                      ͼ    
                                        ͸      
                                   Ĵ-
                                         ;


 Number
                                             ͻ
 digit
                              ͸         ͼ  
        #     
               ͻ       ;
             Ķdigit
                ͼ


 Label
                                ͻ
                           identifierĿ
                               ͼ   
                                 ͻ      
 digit
                                 ͼ  
                               


 Uselist
                                 Ŀ
      Ŀ      ͻ     ͸     ͻ      ͸ 
 USESidentifier(identifier)
          ͼ      ;    ͼ     ;   
  ϸ         ϸ                              ͸                
  ;         ,                        Ĵ,        
  ;         ;                               ;                 
                                                                  
   


 Declarations
 
  Ĵ
       Ŀ                  ͻ                    ͸      
  LABELlabel;Ĵ
                        ͼ                   ;      
                                 ͸                              
                             Ĵ,                          
                                  ;                               
    Ŀ      ͻ     ͸     ͻ      ͸     
  CONSTidentifier=expression;Ĵ
         ͼ     ;     ͼ      ;    
                
       Ŀ     ͻ     ͸     ͻ      ͸          
  TYPEidentifier=type;Ĵ
           ͼ     ;     ͼ      ;         
                 
        Ŀ                         ͻ                  
  VARattributesĿ  
                                ͼ                 
     
                    Ŀ                              
      ͻ    ͻ    ͸     ͻ      ͸    
   identifierattributes:type;Ĵ
      ͼ     ͼ    ;     ͼ      ;   
                    ͸                                          
   Ĵ,                            
                    ;                                           
     
       Ŀ     ͻ     Ŀ     ͻ     ͸     
  VALUEvariable:=expression;Ĵ
           ͼ          ͼ     ;    
                   
         ͻ                ͸                 ͻ        
  heading;body
          ͼ                ;                 ͼ


 Heading
               Ŀ               ͻ
 PROCEDUREidentifierĿ
                            ͼ                   
              Ŀ                                              
            FUNCTION                                           
                                                      ͸     
    Ĵ(Ĵ
          Ŀ                                                ;     
      VARĿ                                                   
                                                                
         Ŀ                                                      
      VARSĴ                                                   
                ͻ    ͸    ͻ      ͸   
    identifier:identifier)Ĵ
        Ŀ      ͼ   ;    ͼ    ;   
      CONSTĴ        ͸                                    
            Ĵ,                               
        Ŀ           ;                                     
      CONSTS                                                 
                    ͻ                               
      heading         
                             ͼ                                
                            ͸                                       
     Ĵ;        
                             ;                                        
     
     
     
             ͸        ͻ            ͻ  
       :identifier        attributes
              ;        ͼ              ͼ


 Attributes
        Ŀ
    ͸     ͻ     ͻ   ͸    ͻ    ͸
 [identifiernumber:number]
    ;     ͼ      ͼ    ;    ͼ    ;
                                 ͸                       
          Ĵ,
                                  ;


 Type
 Ŀ       
                    Ŀ      Ŀ     Ŀ     Ŀ              
                    ADROF     ADSOF              
                                            Ѿ      
           
          ͻ                                                 
    identifierĴ
          ͼ          ͸     ͻ     ͸         
                              (expression)       
                                 ;    ͼ    ;          
                                             ͸                     
                                      Ĵ,               
                                              ;                      
                 ͸          ͻ           ͸               
    (identifier)Ĵ
                 ;         ͼ          ;               
                                 ͸                                 
                         Ĵ,                        
                                  ;                                  
              ͻ        ͸       ͻ              
    expression..expressionĴ
              ͼ        ;       ͼ              
    Ŀ      
                  Ŀ           Ŀ                      
               SUPER      PACKED                   
                                                       
          
                   Ŀ                    ͸                      
    ARRAY[Ŀ      
                                       ;                     
                
               ͻ   ͸   ͸      ͸    Ŀ     ͻ  
          expression..*]OFtypeĴ
              ͼ   ;   ;    ;         ͼ  
                       ͻ                                      
            type                           
                        ͼ                                       
                          ͸                                        
           Ĵ,                          
              Ŀ     ;        ͻ          Ŀ          
    RECORDfieldsENDĴ
                              ͼ                    
             Ŀ                  Ŀ              ͻ           
    SETOFtypeĴ
                                             ͼ           
             Ŀ                 Ŀ              ͻ           
    FILEOFtype
                                             ͼ


 Fields
         ͻ                                          ͸
 identifier:Ŀ
      ͼ      ͸     ͻ     ͸     ;        
                     [expression]              
                         ;     ͼ     ;                 
                             ͸                                      
    Ĵ,             
                 ͸          ;       ͻ                          
  Ĵ;Ķtype
                  ;                   ͼ
  Ŀ
    Ŀ  ͻ                             ͸  ͻ   
  CASEidentifier:identifierĿ 
       ͼ  ͸  ͻ  ͸   ;  ͼ  
                          Ĵ[expression]                    
                            ;  ͼ  ;                       
   
    Ŀ    ͻ     ͸      ͸    ͻ     ͸                 
  OFcases:(fields)Ĵ
        ͼ     ;      ;    ͼ     ;               
                                 ͸                         ͸       
          Ĵ; ;
                                  ;                           ;


 Body
     Ŀ
       ͻ    Ŀ    ͻ     Ŀ     ͸ 
 declarationsBEGINstatementEND;
       ͼ       ͼ        ;
                                       ͸               
                                 Ĵ;          
                                        ;                
                                     Ŀ              
     EXTERNĴ
                                                   
                                     Ŀ             
     FORWARD
                                      


 Statement
                              ͻ                      ͸
 label:Ŀ
                             ͼ                      ;        
 
         ͻ                Ŀ              ͻ
 variable:=expression
         ͼ                              ͼ     
                      Ŀ  
       ͻ         ͸        ͻ         ͸     
 identifier(expression)Ĵ
       ͼ          ;       ͼ        ;      
                                           ͸                      
                                    Ĵ,              
          Ŀ              ͻ  ;       Ŀ           
 BEGINstatementENDĴ
                       ͼ                      
                                  ͸                               
                           Ĵ;                        
                                   ;                                
             ͸               ͻ                ͸         
 [statement]Ĵ
             ;              ͼ               ;         
                                  ͸                               
                           Ĵ;                        
                                   ;                                
      Ŀ        ͻ         Ŀ         ͻ     
 WITHexpressionDOstatementĴ
             ͼ                 ͼ     
                       ͸                                          
                Ĵ,                                  
                        ;                                           
                  Ŀ                                             
 BREAKĴ
                                                           
                 Ŀ                   ͻ                
              CYCLE            label             
                                       ͼ                 
                  Ŀ                      ͻ                 
 GOTOlabelĴ
                                        ͼ                 
                               Ŀ                               
 RETURNĴ
                                                              
                        ͻ                        
 controlled statementĴ
                        ͼ                        
 


 Controlled Statement
           Ŀ        ͻ        Ŀ              
  IFboolean expressionTHENĿ    
                   ͼ                     
           
                            Ŀ     
          ͻ          Ŀ           ͻ         
       statementELSEstatementĴ
           ͼ                      ͼ          
     Ŀ     ͻ      Ŀ      ͻ   
  REPEATstatementUNTILboolean expressionĴ
         ͼ           ͼ   
                     ͸                                             
               Ĵ;                                       
                      ;                                              
      Ŀ     ͻ       Ŀ      ͻ     
  WHILEboolean expressionDOstatementĴ
           ͼ             ͼ     
      Ŀ              ͻ      ͸     ͻ       
  FORidentifier:=expressionĿ   
          Ŀ   ͼ      ;     ͼ      
             VAR                                               
                                                                 
          
              Ŀ                                                    
         TOĿ                                               
                                                                
           Ŀ     ͻ        Ŀ      ͻ   
       DOWNTOexpressionDOstatementĴ
                   ͼ              ͼ   
                Ŀ           ͻ           Ŀ           
  CASEexpressionOFĿ    
                            ͼ                     
          
           ͻ     ͸      ͻ            Ŀ           
      cases:statementEND
           ͼ     ;      ͼ         
                             ͸                 
        Ĵ;    
                              ;                  
        Ŀ
            Ŀ                 ͻ              
      OTHERWISEstatement
                             ͼ  
                                            ͸      
                                     Ĵ;
                                             ;


 Boolean Expression
     ͻ
 expression
    ͼ                           
                         Ŀ    Ŀ   Ŀ   Ŀ
                         ANDTHEN   ORELSE
                                   
  


 Expression
     ͻ
 simple
    ͼ                                          
                       ͸      ͸      ͸   Ŀ
                    <   <=   >   >=   =   <>   IN
                    Ѿ   ;   Ѿ   ;   Ѿ   ;   
  


 Simple
                      ͻ
 term
         ͸       ͼ                       
      +Ĵ                      Ŀ  Ŀ
         ;                   +   -   OR  XOR
         ͸                   Ѿ   Ѿ     
      -                                 
          ;      


 Term
         ͻ
 factor
        ͼ                                          
                      Ŀ  Ŀ  Ŀ  Ŀ  Ŀ  Ŀ
                  *  /  DIV  MOD  ISR  SHL  SHR  AND
                  Ѿ  Ѿ            
      


 Factor
        ͻ
  identifier
        ͼ         ͸        ͻ         ͸     
                         (expression)  
                              ;       ͼ        ;      
                                            ͸                      
                                     Ĵ,              
                 ͸        ͻ     ; ͸                   
  (expression)Ĵ
                 ;        ͼ         ;                   
                     Ŀ              ͻ                       
  NOTfactorĴ
                                   ͼ                       
                  Ŀ                 ͻ                       
  ADRfactorĴ
                                 ͼ                       
                 Ŀ                                               
             ADS                                            
                                                                  
        Ŀ          Ŀ                
            ͻ        ͸      ͻ       ͸         
  identifier[cases]Ĵ
             ͼ         ;       ͼ        ;         
                              ͻ                               
  constantĴ
                              ͼ                               
                              ͻ                               
  variable
                               ͼ


 Cases
                           Ŀ
            ͻ      ͸          ͻ    
 expression..expression
           ͼ       ;          ͼ           
                                    ͸                            
        Ĵ,
                                     ;


 Real
                             Ŀ
                 ͻ        ͸          ͻ       
 digit.digitĿ
                ͼ        ;         ͼ                  
                                          
 
     Ŀ
        ͸                                 ͻ             
 Edigit
         ;                             ͼ   
         ͸        ͸               
      eĴ  +Ĵ
         ;        ;   
         ͸        ͸   
      DĴ  -
         ;         ;
         ͸   
      d
          ;


 Variable
      ͻ
 identifier
      ͼ        ͸        ͻ         ͸     
                      [expression]Ĵ  
                          ;       ͼ        ;     
                                        ͸                     
                                 Ĵ,             
                                         ;                      
                              ͸      ͻ               
                      .identifierĴ  
                              ;      ͼ               
                                         ͸                      
                        
                                          ;                       
                    


 Constant
                         ͻ                ͸
 identifier(Ŀ   
                        ͼ                ;               
          
         Ŀ                       
           Ŀ       ͻ     Ŀ    ͻ    ͸  
       DOexpressionOFexpression)Ĵ
                   ͼ          ͼ   ;  
                                   ͸                               
       Ĵ,       
                                    ;                                
                ͸             ͻ            ͸             
   ,character,Ĵ
              ;           ͼ          ;           
                            ͸     ͸                        
                        ,,                     
                             ;     ;                         
                                       
                              ͻ                           
           constant         
                               ͼ                            
                                  ͸                                
        Ĵ*      
                                   ;                                 
                                   Ŀ                               
   NILĴ
                                                                  
                                 ͻ                              
   numberĴ
                                 ͼ                              
                                  ͻ                               
   real
                                   ͼ





 Appendix B  Microsoft Pascal Features and the ISO Standard

 

 B.1  Microsoft Pascal and the ISO Standard

 B.2  Summary of Microsoft Pascal Features

       B.2.1  Syntactic and Pragmatic Features

       B.2.2  Data types

       B.2.3  Operators and Intrinsics

       B.2.4  Control Flow and Structure Features

       B.2.5  Extend Level I/O and Files

       B.2.6  System Level I/O



 Microsoft Corporation fully supports the effort to standardize the
 Pascal language. A Microsoft representative sits on the ANSI/IEEE
 committee. At this writing, the ISO Pascal standard, Level 0 and
 Level 1, is still in draft status.

 MS-Pascal generally conforms to this current draft standard, but does
 not yet implement the proposed conformant array mechanism. This
 controversial method of passing arrays of different bounds as one
 parameter type has not been tested, and the details change from draft
 to draft. The conformant array scheme is not part of the ANSI/IEEE
 standard nor the ISO Level 0 standard.

 The super array type in MS-Pascal provides conformant array parameters,
 as well as dynamic length arrays allocated on the heap. Programs
 correctly written to the ISO standard (Level 0) or to the ANSI/IEEE
 standard should run correctly, without changes, under MS-Pascal.
 However, since MS-Pascal features introduce new reserved words and
 other elements, this goal cannot be fully realized.


 B.1  Microsoft Pascal and the ISO Standard


 The ISO standard defines a large number of error conditions, but
 allows a particular implementation to handle an error by documenting the
 fact that the error is not caught. These "errors not caught," and other
 differences between MS-Pascal and the ISO standard, are described below.
 An MS-Pascal program that conforms or tests conformance to the ISO standard
 must have both the metacommands $standard and $debug on.

 MS-Pascal allows the following minor extensions to the current
 ISO/ANSI/IEEE standard:

     1.  a question mark (?) as a substitute for the up arrow (^)

     2.  the underscore (_) in identifiers

 Due to the way the compiler binds identifiers, the new reserved words
 added at the extend and system levels cannot be used as identifiers at the
 standard level. A new directive, EXTERN, and new predeclared functions are
 standard in MS-Pascal.

 The current differences between Microsoft Pascal at the standard level and
 the current ISO/ANSI/IEEE standard are summarized in the following pages.

     1.  The ISO standard requires a separator between numbers and
         identifiers or keywords.

         In some cases, MS-Pascal doesn't require a separator between a
         number and an identifier or keyword, e.g., "100mod" is accepted as
         "100 mod" without error.

     2.  The ISO standard does not allow passing a component of a PACKED
         structure as a reference parameter.

         MS-Pascal specifically permits passing a CHAR element of a PACKED
         ARRAY [1 . . n] OF CHAR as a reference parameter. Passing a tag
         field as a reference is an error not caught. Passing other packed
         components gives the usual error.

     3.  The ISO standard does not include the textfile line-marker
         character in the set of CHAR values.

         MS-Pascal permits all 256 8-bit values as CHAR values; with some
         operating systems, a particular CHAR value (e.g., carriage return)
         is also the line marker character.

     4.  The ISO standard requires a variant to be given for all possible
         tag values.

         MS-Pascal permits a variant record declaration in which not all tag
         values are given.

     5.  The ISO standard requires that an identifier have only one meaning
         in any scope.

         In MS-Pascal, using an identifier and then redeclaring it in the
         same scope is an error not caught. For example, the following,

              CONST X = Y; VAR Y : CHAR;

         has two meanings for Y in the same scope. MS-Pascal generally uses
         the latest definition for an identifier. There is one ambiguous
         case: if you declare type FOO in one scope and in an inner scope
         TYPE P = ^ FOO; FOO = type; then FOO has two meanings and intent is
         ambiguous. In this case, the compiler uses the later definition of
         FOO and issues a warning.

     6.  The ISO standard requires field width "M" to be greater than zero
         in WRITE and WRITELN procedures.

         MS-Pascal treats M < 0 as if M = ABS (M), but field expansion takes
         place from the right rather than the left. M can also be zero, to
         WRITE nothing. Textfile READ (LN) and WRITE (LN) parameters can
         take both M and N parameters (ignored if not needed). The form
         "V::N" is allowed. When writing an INTEGER, the N parameter sets
         the output radix; when reading or writing an enumerated type, the N
         parameter sets the ordinal number or constant identifier option.

     7.  The ISO standard does not allow a variable created with the long
         form of NEW to be assigned, used in an expression, or passed as a
         parameter. However, this is difficult to check for at compile time
         and expensive to check at runtime.

         MS-Pascal allows assignments to these variables using the actual
         length of the target variable. The ISO standard error is not
         caught.

     8.  The ISO standard does not allow the short form of DISPOSE to be
         used on a structure allocated with the long form of NEW. The ISO
         standard only permits a variable allocated with the long form of
         NEW to be released with the long form of DISPOSE, and all tag
         fields should never change between the calls.

         MS-Pascal allows the short form of DISPOSE to be used on a
         structure allocated with the long form of NEW, and does not check
         for changes in tag values.

     9.  The ISO standard declares that when a "change of variant" occurs
         (such as when a new tag value is assigned), all the variant fields
         become undefined.

         MS-Pascal does not set the fields uninitialized when a new tag is
         assigned and so does not catch use of a variant field with an
         undefined value.

    10.  The ISO standard does not allow a variable with an active reference
         (i.e., the records of an executing WITH statement or an actual
         reference parameter) to be disposed (if a heap variable) or changed
         by a GET or PUT (if a file buffer variable).

         MS-Pascal does not catch these as errors.

    11.  The ISO standard currently defines I MOD J as an error if J < 0 and
         the result of MOD is positive, even if I is negative.

         MS-Pascal does not currently use the new draft standard semantics
         for the MOD operator. Programs intended to be portable should not
         use MOD unless both operands are positive.

    12.  The ISO standard at Level 1 defines conformant array.

         MS-Pascal does not implement the conformant array concept in Level
         1 of the ISO standard. Super arrays provide much the same
         functionality in a more flexible way.

    13.  The ISO standard requires the control variable of a FOR loop to be
         local to the immediate block. Any assignment to this control
         variable is an error.

         MS-Pascal allows a nonlocal variable to be used if it is STATIC, so
         either a local variable or one at the PROGRAM level can be a FOR
         statement control variable. MS-Pascal also does not detect an
         assignment to the control variable as an error if assignment occurs
         in a procedure or function called within the FOR statement.

    14.  The ISO standard requires the CHR argument to be INTEGER.

         MS-Pascal allows CHR to take any ordinal type.


 B.2  Summary of Microsoft Pascal Features


 This outline summarizes MS-Pascal extensions to the ISO standard.
 Unless otherwise noted, all are at the extend level.


 B.2.1  Syntactic and Pragmatic Features


     1.  The metalanguage (standard level)

              $brave                   $page
              $debug                   $pageif
              $decmath                 $pagesize
              $entry                   $pop
              $errors                  $push
              $extend                  $rangeck
              $floatcalls              $real
              $goto                    $rom
              $if $then $else $end     $runtime
              $include                 $simple
              $inconst                 $size
              $indexck                 $skip
              $initck                  $speed
              $integer                 $stackck
              $line                    $standard
              $linesize                $subtitle
              $list                    $symtab
              $mathck                  $system
              $message                 $tagck
              $nilck                   $title
              $ocode                   $warn
              $optbug

          2.  Extra listing (standard level)

              1.  flags for jumps, globals, identifier level, control level,
                  header, trailer

              2.  textual error and warning messages

          3.  Syntactic additions

              1.  ! as comment to end of line

              2.  square brackets equivalent to BEGIN/END

          4.  Nondecimal number notation

              1.  numeric constants with # or nn# (where
                   nn = 2..36)

              2.  DECODE/READ takes # notation

              3.  ENCODE/WRITE with N of 2, 8, 10, 16

          5.  Extended CASE range

              1.  for CASE statements and record variants

              2.  OTHERWISE for all other values

              3.  A..B for range of values


 B.2.2  Data Types and Modes


     1.  WORD type, WRD function, MAXWORD constant

     2.  REAL4 and REAL8 types

     3.  INTEGER4 type, MAXINT4 constant:

     4.  FLOAT4, ROUND4, and TRUNC4 functions

     5.  Address types (system level)

         1.  ADR and ADS types and operators

         2.  VARS and CONSTS parameters

     6.  SUPER array types

         1.  conformant parameters

         2.  dynamic length heap variables

         3.  multidimensional super arrays

         4.  STRING and LSTRING super types

     7.  LSTRING type, NULL constant, .LEN field

     8.  Explicit byte offsets in records (system level)

     9.  CONST and CONSTS reference parameters for constants and expressions

    10.  Structured (array, record, and set) constants

    11.  Extended functions returning any assignable type

    12.  Variable selection on values returned from functions

    13.  Attributes

         EXTERN          PORT
         EXTERNAL        PUBLIC
         FORTRAN         PURE
         INTERRUPT       READONLY
         ORIGIN          STATIC


 B.2.3  Operators and Intrinsics


     1.  Extend level operators:

         1.  shift operators: SHL SHR ISR

         2.  bitwise logical: AND  OR NOT XOR

         3.  set operators: < >

     2.  Constant expressions:

         1.  string constant concatenation with * operator

         2.  numeric, ordinal, Boolean expressions in type clauses

         3.  other constant functions:

             CHR         UPPER
             DIV         WRD
             HIBYTE      *
             HIWORD      +
             LOBYTE      -
             LOWER       <
             LOWORD      <=
             MOD         <>
             ORD         =
             RETYPE      >
             SIZEOF      >=

     3.  Additional intrinsic functions at extend level:

             ABORT         HIWORD
             BYLONG        LOBYTE
             BYWORD        LOWER
             DECODE        LOWORD
             ENCODE        RESULT
             EVAL          SIZEOF
             HIBYTE        UPPER

     4.  Additional intrinsic functions at system level:

             FILLC         MOVESL
             FILLSC        MOVESR
             MOVEL         RETYPE
             MOVER

     5.  Intrinsic functions that operate on strings:

         1.  for STRING or LSTRING: COPYSTR POSITN SCANEQ SCANNE

         2.  for LSTRING only: CONCAT INSERT DELETE COPYLST

     6.  MS-FORTRAN REAL library functions (standard level)

     7.  MS-Pascal library functions (standard level):

             ALLHQQ      MARKAS
             BEGOQQ      MEMAVL
             BEGXQQ      PLYUQQ
             DATE        PTYUQQ
             DISBIN      RELEAS
             ENDOQQ      SADDOK
             ENDXQQ      SMULOK
             ENABIN      TICS
             FREECT      TIME
             GTYUQQ      UADDOK
             LADDOK      UMULOK
             LMULOK      UNLOCK
             LOCKED      VECTIN


 B.2.4  Control Flow and Structure Features


 1.  Control flow statements: BREAK, CYCLE, and RETURN

 2.  Sequential control operators: AND THEN and OR ELSE in IF, WHILE,
     REPEAT

 3.  Extended FOR loop: FOR VAR variable

 4.  VALUE section to initialize static variables

 5.  Mixed order LABEL, CONST, TYPE, VAR, VALUE sections

 6.  Compilable MODULES, with global attributes

 7.  UNIT INTERFACE and IMPLEMENTATION:

     1.  interface version numbers, version checking

     2.  optional rename of constituents

     3.  guaranteed unique unit initialization

     4.  optional unit initialization


 B.2.5  Extend Level I/O and Files


     1.  Textfile line length declaration, TEXT (nnn)

     2.  READ enumerated, Boolean, pointer, STRING, LSTRING

     3.  WRITE enumerated, pointer, LSTRING

     4.  Negative M value to justify left instead of right

     5.  Temporary files

     6.  DIRECT mode files, SEEK procedure

     7.  ASSIGN, CLOSE, DISCARD, READSET, READFN procedures

     8.  FILEMODES type and constants, F.MODE access

     9.  Error trapping, F.TRAP and F.ERRS access

     10.  Enumerated I/O using identifier as string


 B.2.6  System level


 The MS-Pascal extension to the ISO standard offers full FCBFQQ type
 equivalent to FILE types.



 Appendix C  Microsoft Pascal and Other Pascals

 

 C.1  Implementations of Pascal

 C.2  Microsoft Pascal and UCSD Pascal



 At the standard level, Microsoft Pascal conforms to the current ISO
 draft standard. In theory, therefore, programs written in accordance with
 the ISO standard are portable and can be compiled with any MS-Pascal
 compiler with no problem.

 In practice, however, the majority of Pascal programs are written
 with at least some nonstandard features. In these cases, it is necessary to
 alter the Pascal source file to conform to the conventions used in
 Microsoft Pascal.


 C.1  Implementations of Pascal


 The areas in which different implementations of the Pascal language
 differ from one another fall into one of the following categories:

     1.  Interactive I/O

         MS-Pascal implements lazy evaluation to handle interactive I/O in a
         natural way. Other Pascals may implement this feature in different
         ways. For example, some systems require an initial READLN.

     2.  String handling

         MS-Pascal supports the super array type LSTRING to handle variable
         length strings efficiently. The ISO standard provides the PACK and
         UNPACK procedures for dealing with strings; other Pascals often
         have some improvement on the string handling facilities described
         in the standard.

     3.  Compiler controls

         Compiler controls implemented either as command line switches or as
         commands within source comments vary from Pascal to Pascal. To
         ensure portability, eliminate all embedded controls from comments.

     4.  Maximum set size

         The maximum set size varies from Pascal to Pascal. Some Pascals
         limit set size to 16 or 64 elements. In MS-Pascal, sets may
         contain up to 256 elements. This allows support of the SET OF
         CHAR.

     5.  Type compatibility

         The rules for type compatibility vary in their strictness. In some
         Pascals, structurally equivalent types with different names are
         compatible; in others (and in the ISO standard), they are not.

     6.  Out of block GOTOs

         Some Pascals do not permit the out-of-block GOTOs that are
         permitted in MS-Pascal.

     7.  Heap management

         Rather than use the procedures NEW and DISPOSE for managing dynamic
         allocation of memory, some Pascals use the MARK and RELEASE
         procedures. MS-Pascal supports both methods. (MARKAS and RELEAS
         are the MS-Pascal names for MARK and RELEASE.)

     8.  OTHERWISE in CASE statements and variant records

         If OTHERWISE is omitted in a CASE statement, control does not
         automatically pass to the next executable statement as in some
         other extended Pascals. Also, some other Pascals use the word ELSE
         or OTHERS instead of OTHERWISE.

     9.  Assigning filenames

         The ASSIGN procedure in MS-Pascal sets an operating system filename
         for a file. Some other Pascals use a second parameter to RESET and
         REWRITE for the filename.

    10.  Separate compilation

         Most Pascals exclude the EXTERN (or EXTERNAL) directive for
         procedures and functions. Many support the idea of a MODULE and/or
         an INTERFACE and IMPLEMENTATION, although the syntax may differ.
         Some do not support PUBLIC and EXTERN variables, but may use a
         FORTRAN COMMON approach. In the latter case, for portability, you
         should give all global variables in one MS-Pascal VAR section,
         using [PUBLIC] in the PROGRAM and [EXTERN] in the MODULE, and
         $include the same variable declarations in each.

    11.  Program parameters

         Some Pascals ignore program parameters. In some Pascals, all files
         must be program parameters.

    12.  Procedural parameters

         Several Pascals do not permit passing procedures and functions as
         parameters. Many do not permit passing any predeclared procedures
         or functions.


 C.2  Microsoft Pascal and UCSD Pascal


 Because UCSD Pascal(R) is one of the more prevalent Pascals for
 microcomputers, conversion of source files from UCSD to MS-Pascal, and vice
 versa, is likely to be a common occurrence. This section discusses the
 differences and similarities between the two Pascals.

 MS-Pascal has incorporated many of the UCSD extensions in one form or
 another. Table C.1 compares UCSD extensions with similar extensions
 available in MS-Pascal.


 Table C.1
 Microsoft Pascal and UCSD Pascal
ķ
 UCSD Extension                     MS-Pascal Equivalent
 
 ATAN                               ARCTAN
 BLOCKREAD                          GETUQQ
 BLOCKWRITE                         PUTUQQ
 UCSD Extension                     MS-Pascal Equivalent
BLOCKWRITE                         PUTUQQ
 CLOSE                              CLOSE
 CLOSE (F, LOCK)                    CLOSE (F)
 CLOSE (F, PURGE)                   DISCARD (F)
 CONCAT                             CONCAT
 COPY                               COPYLST or MOVEL
 DELETE                             DELETE
 EXIT                               RETURN or GOTO
 FILLCHAR                           FILLC and FILLSC
 HALT                               ENDXQQ
 INSERT                             INSERT
 IORESULT, $I                       ERRS and TRAP fields
 LENGTH                             .LEN or STR [0]
 LOG                                LNDRQQ
 MARK                               MARKAS
 MEMAVAIL                           MEMAVL
 MOVELEFT                           MOVEL and MOVESL
 MOVERIGHT                          MOVER and MOVESR
 POS                                POSITN
 RELEASE                            RELEAS
 UCSD Extension                     MS-Pascal Equivalent
RELEASE                            RELEAS
 SCAN                               SCANEQ and SCANNE
 SEEK                               SEEK
 SIZEOF                             SIZEOF
 STR                                ENCODE
 STRING [n]                         LSTRING (n)
 UNIT                               UNIT
 Untyped Files                      FCBFQQ type

 The following notes describe comparative points of interest.

     1.  The UCSD STRING [n] type is logically similar to the MS-Pascal
         LSTRING (n) type. Both contain the length of a variable length
         string in element zero of an ARRAY of CHAR.

     2.  UCSD Pascal allocates pointer variables on the heap with MARK and
         RELEASE. Other Pascals normally use NEW and DISPOSE. MS-Pascal
         permits both methods of dynamic memory allocation.

     3.  MS-Pascal units are like UCSD Pascal units, with the following
         exceptions. In MS-Pascal, an INTERFACE must appear first in any
         compiland using it. Since UCSD Pascal has its own special file
         system, the name of the unit can be used to find the interface
         filename in a standard way.

         MS-Pascal requires a list of all identifiers exported from the unit
         in the UNIT clause itself and makes it optional in a USES clause.
         Different identifiers may be given in a USES clause to avoid
         identifier conflicts.

         Finally, MS-Pascal provides for unit initialization code and
         interface version control. Neither of these are available in UCSD
         Pascal.

     4.  CONCAT is a function in UCSD Pascal; in MS-Pascal, it is a
         procedure.

     5.  In UCSD Pascal, when a CASE statement whose control value does not
         select a statement is executed, the statement following the CASE
         statement is executed. In MS-Pascal, you must include an empty
         OTHERWISE clause to obtain this effect.

     6.  UCSD Pascal permits the use of the EOF (F) and EOLN (F) functions
         on a closed file; in MS-Pascal, this is an error.

     7.  UCSD Pascal permits comparison of records and arrays with the equal
         sign (=) and the not-equal sign (<>). In MS-Pascal, you must RETYPE
         the records and arrays to the same length STRING type, and then
         compare them as strings.



 Appendix D  ASCII Character Codes

 


 Table D.1
 ASCII Character Codes
ķ
 Dec     Hex     CHR               Dec     Hex     CHR
 
 Dec     Hex     CHR               Dec     Hex     CHR
 
 000     00H     NUL               064     40H     @
 001     01H     SOH               065     41H     A
 002     02H     STX               066     42H     B
 003     03H     ETX               067     43H     C
 004     04H     EOT               068     44H     D
 005     05H     ENQ               069     45H     E
 006     06H     ACK               070     46H     F
 007     07H     BEL               071     47H     G
 008     08H     BS                072     48H     H
 009     09H     HT                073     49H     I
 010     0AH     LF                074     4AH     J
 011     0BH     VT                075     4BH     K
 012     0CH     FF                076     4CH     L
 013     0DH     CR                077     4DH     M
 014     0EH     SO                078     4EH     N
 015     0FH     SI                079     4FH     O
 016     10H     DLE               080     50H     P
 017     11H     DC1               081     51H     Q
 018     12H     DC2               082     52H     R
 Dec     Hex     CHR               Dec     Hex     CHR
018     12H     DC2               082     52H     R
 019     13H     DC3               083     53H     S
 020     14H     DC4               084     54H     T
 021     15H     NAK               085     55H     U
 022     16H     SYN               086     56H     V
 023     17H     ETB               087     57H     W
 024     18H     CAN               088     58H     X
 025     19H     EM                089     59H     Y
 026     1AH     SUB               090     5AH     Z
 027     1BH     ESCAPE            091     5BH     [
 028     1CH     FS                092     5CH     \
 029     1DH     GS                093     5DH     ]
 030     1EH     RS                094     5EH     ^
 031     1FH     US                095     5FH     ^
 032     20H     SPACE             096     60H     '
 033     21H     !                 097     61H     a
 034     22H     "                 098     62H     b
 035     23H     #                 099     63H     c
 036     24H     $                 100     64H     d
 037     25H     %                 101     65H     e
 Dec     Hex     CHR               Dec     Hex     CHR
037     25H     %                 101     65H     e
 038     26H     &                 102     66H     f
 039     27H     '                 103     67H     g
 040     28H     (                 104     68H     h
 041     29H     )                 105     69H     i
 042     2AH     *                 106     6AH     j
 043     2BH     +                 107     6BH     k
 044     2CH     ,                 108     6CH     l
 045     2DH     -                 109     6DH     m
 046     2EH     .                 110     6EH     n
 047     2FH     /                 111     6FH     o
 048     30H     0                 112     70H     p
 049     31H     1                 113     71H     q
 050     32H     2                 114     72H     r
 051     33H     3                 115     73H     s
 052     34H     4                 116     74H     t
 053     35H     5                 117     75H     u
 054     36H     6                 118     76H     v
 055     37H     7                 119     77H     w
 056     38H     8                 120     78H     x
 Dec     Hex     CHR               Dec     Hex     CHR
056     38H     8                 120     78H     x
 057     39H     9                 121     79H     y
 058     3AH     :                 122     7AH     z
 059     3BH     ;                 123     7BH     {
 060     3CH     <                 124     7CH     |
 061     3DH     =                 125     7DH     }
 062     3EH     >                 126     7EH     ~
 063     3FH     ?                 127     7FH     DEL


 Dec=decimal, Hex=hexadecimal (H), CHR=character,LF=Line Feed,
 FF=Form Feed, CR=Carriage Return, DEL=Rub out



 Appendix E  Summary of Microsoft Pascal Reserved Words

 

 Reserved words at the standard level:

      AND                 NIL
      ARRAY               NOT
      BEGIN               OF
      CASE                OR
      CONST               PACKED
      DIV                 PROCEDURE
      DO                  PROGRAM
      DOWNTO              RECORD
      ELSE                REPEAT
      END                 SET
      FILE                THEN
      FOR                 TO
      FUNCTION            TYPE
      GOTO                UNTIL
      IF                  VAR
      IN                  WHILE
      LABEL               WITH
      MOD

 Additional reserved words at the extend level:

      BREAK               RETURN
      CONSTS              SHL
      CYCLE               SHR
      IMPLEMENTATION      UNIT
      INTERFACE           USES
      ISR                 VALUE
      MODULE              VARS
      OTHERWISE           XOR

 Additional reserved words at the system level:

      ADR
      ADS

 Names of attributes:

      EXTERN              PORT
      EXTERNAL            PUBLIC
      FORTRAN             PURE
      INTERRUPT           READONLY
      ORIGIN              STATIC

 Names of directives:

      EXTERN
      EXTERNAL
      FORWARD

 Logically, directives are reserved words. Since additional directives
 are allowed in ISO Pascal, all are included at the standard level. Note
 that EXTERN is both a directive and an attribute; EXTERNAL is a synonym for
 EXTERN in both cases. This provides compatibility with a number of other
 Pascals.



 Appendix F  Summary of Available Procedures and Functions

 

 This appendix provides a summary listing of all available functions and
 procedures, along with the name of the group in which they are presented in
 Section 15.1, "Categories of Available Procedures and Functions."


 Table F.1
 Procedures and Functions
ķ
 Name     Description                    Category
 
 ABORT    Terminate program              Extend level
 ABS      Absolute value function        Arithmetic
 ACDRQQ   REAL8 arc cosine function      Arithmetic
 ACSRQQ   REAL4 arc cosine function      Arithmetic
 AIDRQQ   REAL8 truncate function        Arithmetic
 AISRQQ   REAL4 truncate function        Arithmetic
 ALLHQQ   Allocate heap item             Library
 ALLMQQ   Segmented heap management      Library
 ANDRQQ   REAL8 round toward zero        Arithmetic
 ANSRQQ   REAL4 round toward zero        Arithmetic
 ARCTAN   Arc tangent function           Arithmetic
 ASDRQQ   REAL8 arc sine function        Arithmetic
 Name     Description                    Category
ASDRQQ   REAL8 arc sine function        Arithmetic
 ASSRQQ   REAL4 arc sine function        Arithmetic
 ASSIGN   Assign filename                File system
 ATDRQQ   REAL8 arc tangent function     Arithmetic
 ATSRQQ   REAL4 arc tangent function     Arithmetic
 A2DRQQ   REAL8 arc tangent (A/B)        Arithmetic
 A2SRQQ   REAL4 arc tangent (A/B)        Arithmetic
 BEGOQQ   Initialize user                Library
 BEGXQQ   Overall initialization         Library
 BYLONG   WORD or INTEGER to INTEGER4    Extend level
 BYWORD   Put bytes in word              Extend level
 CHDRQQ   REAL8 hyperbolic cosine        Arithmetic
 CHR      Get ASCII char of value        Data conversion
 CHSRQQ   REAL4 hyperbolic cosine        Arithmetic
 CLOSE    Close file                     File system
 CNDRQQ   REAL8 cosine function          Arithmetic
 CNSRQQ   REAL4 cosine function          Arithmetic
 CONCAT   Concatenate LSTRING            String
 COPYLST  Copy to LSTRING                String
 COPYSTR  Copy to STRING                 String
 Name     Description                    Category
COPYSTR  Copy to STRING                 String
 COS      Cosine function                Arithmetic
 DATE     Date function                  Library
 DECODE   Decode LSTRING to variable     Extend level
 DELETE   Remove portion of LSTRING      String
 DISBIN   Disable interrupts             Library
 DISCARD  Close and delete file          File system
 DISMQQ   Segmented heap management      Library
 DISPOSE  Dispose of heap item           Dynamic alloc'n
 ENABIN   Enable interrupts              Library
 ENCODE   Encode expression to LSTRING   Extend level
 ENDOQQ   User termination               Library
 ENDXQQ   Program termination            Library
 EOF      Boolean end-of-file            File system
 EOLN     Boolean end-of-line            File system
 EVAL     Evaluate functions             Extend level
 EXDRQQ   REAL8 exponential function     Arithmetic
 EXP      Exponential function           Arithmetic
 EXSRQQ   REAL4 exponential function     Arithmetic
 FILLC    Fill area with C, relative     System level
 Name     Description                    Category
FILLC    Fill area with C, relative     System level
 FILLSC   Fill area with C, segmented    System level
 FLOAT    Convert INTEGER to REAL        Data conversion
 FLOAT4   Convert INTEGER4 to REAL       Data conversion
 FREECT   Give count of free blocks      Library
 FREMQQ   Segmented heap management      Library
 GET      Get next file component        File system
 GETMQQ   Segmented heap management      Library
 GTYUQQ   Direct terminal input          Library
 HDLUQQ   Returns MS-DOS 2.0 file
          handle for a Pascal file       File system
 HIBYTE   Get high BYTE                  Extend level
 HIWORD   Get high WORD                  Extend level
 INSERT   Insert string                  String
 LADDOK   32-bit signed addition check   Library
 LDDRQQ   REAL8 log base ten function    Arithmetic
 LDSRQQ   REAL4 log base ten function    Arithmetic
 LMULOK   32-bit signed multiply check   Library
 LN       Natural log function           Arithmetic
 LNDRQQ   REAL8 natural log              Arithmetic
 Name     Description                    Category
LNDRQQ   REAL8 natural log              Arithmetic
 LNSRQQ   REAL4 natural log              Arithmetic
 LOBYTE   Get low BYTE                   Extend level
 LOCKED   Resource locked status         Library
 LOWER    Get lower bound                Extend level
 LOWORD   Get low WORD                   Extend level
 MARKAS   Mark heap bounds               Library
 MEMAVL   Available memory               Library
 MDDRQQ   REAL8 modulo function          Arithmetic
 MDSRQQ   REAL4 modulo function          Arithmetic
 MNDRQQ   REAL8 minimum function         Arithmetic
 MNSRQQ   REAL4 minimum function         Arithmetic
 MOVEL    Move bytes left, relative      System level
 MOVER    Move bytes right, relative     System level
 MOVESL   Move bytes left, segmented     System level
 MOVESR   Move bytes right, segmented    System level
 MXDRQQ   REAL8 maximum function         Arithmetic
 MXSRQQ   REAL4 maximum function         Arithmetic
 NEW      Allocate new heap item         Library
 ODD      Boolean odd function           Data conversion
 Name     Description                    Category
ODD      Boolean odd function           Data conversion
 ORD      Get ordinal value              Data conversion
 PACK     Pack CHAR array                Data conversion
 PAGE     Write new page                 File system
 PIDRQQ   REAL8 to INTEGER power         Arithmetic
 PISRQQ   REAL4 to INTEGER power         Arithmetic
 PLYUQQ   Direct terminal end line       Library
 POSITN   Find position of substring     String
 PRED     Predecessor function           Data conversion
 PRDRQQ   REAL8 to REAL8 power           Arithmetic
 PRSRQQ   REAL4 to REAL4 power           Arithmetic
 PTYUQQ   Direct terminal output         Library
 PUT      Put value to file              File system
 READ     Read file                      File system
 READFN   Read filename                  File system
 READLN   Read file to end of line       File system
 READSET  Read set                       File system
 RELEAS   Release heap space             Library
 RESET    Ready file for read            File system
 RESULT   Return result of function      Extend level
 Name     Description                    Category
RESULT   Return result of function      Extend level
 RETYPE   Force expression to type       System level
 REWRITE  Ready file for write           File system
 ROUND    Round REAL to INTEGER          Data conversion
 ROUND4   Round REAL to INTEGER4         Data conversion
 SADDOK   16-bit signed addition check   Library
 SCANEQ   Scan until char found          String
 SCANNE   Scan until char not found      String
 SEEK     Position at direct file record File system
 SHDRQQ   REAL8 hyperbolic sine          Arithmetic
 SHSRQQ   REAL4 hyperbolic sine          Arithmetic
 SIN      Sine function                  Arithmetic
 SIZEOF   Get size of structure          Extend level
 SMULOK   16-bit signed multiply check   Library
 SNDRQQ   REAL8 sine function            Arithmetic
 SNSRQQ   REAL4 sine function            Arithmetic
 SQR      Square function                Arithmetic
 SQRT     Square root function           Arithmetic
 SRDRQQ   REAL8 square root              Arithmetic
 SRSRQQ   REAL4 square root              Arithmetic
 Name     Description                    Category
SRSRQQ   REAL4 square root              Arithmetic
 SUCC     Successor function             Data conversion
 THDRQQ   REAL8 hyperbolic tangent       Arithmetic
 THSRQQ   REAL4 hyperbolic tangent       Arithmetic
 TICS     Time in arbitrary units        Library
 TIME     Time of day function           Library
 TNDRQQ   REAL8 tangent function         Arithmetic
 TNSRQQ   REAL4 tangent function         Arithmetic
 TRUNC    Truncate REAL to INTEGER       Data conversion
 TRUNC4   Truncate REAL to INTEGER4      Data conversion
 UADDOK   Unsigned addition check        Library
 UMULOK   Unsigned multiply check        Library
 UNLOCK   Unlock resource                Library
 UNPACK   Unpack STRING to array         Data conversion
 UPPER    Get upper bound                Extend level
 VECTIN   Set interrupt vector           Library
 WRD      Convert to WORD value          Data conversion
 WRITE    Write file                     File system
 WRITELN  Write line to file             File system



 Appendix G  Summary of Microsoft Pascal Metacommands

 

 This appendix provides a single alphabetical list of all of the
 metacommands described in Chapter 18, "Microsoft Pascal Metacommands."
 Defaults, if any, are shown following the metacommand.


 Table G.1
 Microsoft Pascal Metacommands
ķ
 Metacommand          Action
 
 $brave+              Sends messages to the terminal screen

 $debug-              Turns on or off all error checking (CK)

 $decmath-            Directs the compiler to carry out
 Metacommand          Action
$decmath-            Directs the compiler to carry out
                      floating-point operations using the
                      decimal support routines in DECMATH.LIB

 $entry-              Generates procedure entry and exit
                      calls for debugger

 $errors:25           Sets number of errors allowed per page

 $extend              Adds extend level features

 $floatcalls+         Directs the compiler to generate calls
                      to real number floating-point routines

 $goto-               Flags GOTOs as "considered harmful"

 $if constant         Allows conditional compilation of
   $then text1        text1 source if constant is greater than
   $else text2        zero
 $end
 Metacommand          Action
$end

 $include:'file'      Switches compilation to file named

 $inconst             Allows interactive setting of constant
                      values at compile time

 $indexck-            Checks for array index values in range

 $initck-             Checks for use of uninitialized values

 $integer             Sets the length of the integer type

 $line-               Generates line number calls for debugger

 $linesize:79         Sets width of source listing

 $list+               Turns on or off source listing

 $mathck-             Checks for mathematical errors
 Metacommand          Action
$mathck-             Checks for mathematical errors

 $message             Displays a message on terminal screen

 $nilck-              Checks for bad pointer values

 $ocode+              Turns on or off object code listing

 $page+               Skips to next page

 $page:n              Sets page number for next page

 $pageif:n            Skips to next page if less than
                      n lines left

 $pagesize:55         Sets page length of source listing

 $pop                 Restores saved value of all metacommands

 $push                Saves current value of all metacommands
 Metacommand          Action
$push                Saves current value of all metacommands

 $rangeck-            Checks for subrange validity

 $real                Sets the length of the REAL type

 $rom                 Warns on static initialization

 $runtime-            Determines context of runtime errors

 $simple              Disables global optimizations

 $size                Minimizes size of code generated

 $skip:n              Skips n lines or to end of page

 $speed               Minimizes execution time of code

 $stackck-            Checks for stack overflow at entry

 Metacommand          Action

 $standard            Enables standard level only

 $subtitle:'subt'     Sets page subtitle

 $symtab+             Sends symbol table to source listing

 $system              Adds extend and system level features

 $tagck-              Checks tag fields in variant records

 $title:'title'       Gives page title for source listing

 $warn+               Gives warning messages in source listing





 Index


 Symbol
 
 (>) operator
 (>=) operator
 (<>) operator
 (>=) operator
 ([ and ]) square brackets
 (:=) assignment
 (!) comment to end-of-line
 (*) operator
 (*) operator
 (*) operator
 (+) operator
 (+) operator
 (-) operator
 (-) operator
 (/) operator
 (<=) operator
 (<=) operator
 (=) operator
 (=) operator
 (<) operator
 (<) operator
 (<) operator
 (.) period
 (?) question mark
 (#) radix separator
 (_) underscore


 A
 
 A2DRQQ function
 A2SRQQ function
 ABORT
 ABORT procedure
 ABS function
 ACDRQQ function
 ACSRQQ function
 Actual parameters
 Address Types
 ADR operator
 ADRMEM predeclared type
 ADS operator
 ADSMEM predeclared type
 AIDRQQ function
 AISRQQ function
 Aliases
 ALLHQQ function
 ALLMQQ
 AND operator
 AND THEN operator
 ANDRQQ function
 ANSRQQ function
 Appendix A
 ARCTAN function
 Arithmetic functions
 Arrays
 Arrays
     component type
     conformant
     dynamic
     index type
     n-dimensional
     super
 ASCII character codes
 ASCII character set
 ASCII files
 ASDRQQ function
 ASSIGN procedure
 Assignment compatibility
 Assignment statement
 ASSRQQ function
 ATDRQQ function
 ATSRQQ function
 Attributes
 Attributes
     EXTERN
     EXTERNAL
     for functions
     for procedures
     for variables
     FORTRAN
     INTERRUPT
     ORIGIN
     PORT
     PUBLIC
     PURE
     READONLY
     STATIC
 Available procedures and functions
     summary of


 B
 
 Base type
 BEGIN
 BEGOQQ procedure
 BEGXQQ procedure
 BINARY files
 boolean expression
 BOOLEAN expressions
 Boolean operator
 BOOLEAN type
 BRAVE metacommand
 BREAK statement
 Buffer variable
 BYLONG function
 BYTE predeclared subrange
 BYWORD function


 C
 
 CASE
     constant list
     constant
     constant
     index
     statement
 CHAR type
 Character strings
 CHDRQQ function
 CHR function
 CHSRQQ function
 CLOSE procedure
 CLOSE procedure
 CNDRQQ function
 CNSRQQ function
 Comments
 Compatibility
     assignment
     of types
 Compilable parts of programs
 Compilands
 Compiling programs
 Component type
 Component variable
 Compound statements
 CONCAT procedure
 Concurrent I/O
 Conditional compilation
 Conditional statement
 Conformant array
 CONST
 Constant parameters
 Constants
 Constants
     declarations
     enumerated
     expressions
     identifiers
     identifiers
     length restriction
     string
     structured
     structured
         array
         record
         set
 CONSTS parameters
 CONSTS
 Control flow
 Control variable
 COPYLST procedure
 COPYSTR procedure
 COS function
 CYCLE statement


 D
 
 DATE procedure
 DEBUG metacommand
 Debugging metacommands
 Declarations
     flexible order of
     FORWARD
     function
     identifiers
     procedure
     type
     variables
 DECMATH metacommand
 DECODE function
 DELETE procedure
 Digits
 DIRECT files
 DIRECT
 Directives
     EXTERN
     EXTERNAL
     for functions
     for procedures
     FORWARD
 DISBIN procedure
 DISCARD procedure
 DISMQQ procedure
 DISPOSE procedure
 DIV operator
 DO (in structured constants)
 Dynamic array


 E
 
 Empty statement
 Empty variant
 EMSEQQ
 ENABIN procedure
 ENCODE function
 END
 ENDOQQ procedure
 ENDXQQ procedure
 ENTGQQ
 Entire variable
 ENTRY metacommand
 Enumerated
     constants
     I/O
     types
 EOF function
 EOLN function
 ERRORS metacommand
 EVAL procedure
 EXDRQQ function
 EXP function
 Explicit field offsets
 Expressions
     constant
     simple
 EXSRQQ function
 Extend level
     CASE constant
     FOR-LOOP
     function
     intrinsics
     I/O
     Pascal
 EXTEND metacommand
 EXTERN attribute
 EXTERN directive
 EXTERNAL attribute
 EXTERNAL directive


 F
 
 FCBFQQ
 Features of MS-Pascal
 Features
     constant expressions
     structured constants
     VALUE section
 Fields
     identifiers
     variables
 Files
     buffer variable
     FCB fields
         ERRS
         MODE
         TRAP
     FCBFQQ
     INPUT
     modes
         DIRECT
         SEQUENTIAL
         TERMINAL
     OUTPUT
     structures
         ASCII
         BINARY
     temporary
 FILLC procedure
 FILLSC procedure
 Flexible order of declarations
 FLOAT function
 FLOAT4 function
 FLOATCALLS metacommand
 FOR statement
 FOR VAR feature
 formal parameters
 Formatting parameters
 Formatting rules
 FORTRAN attribute
 FORTRAN library
 FORWARD directive
 Forward pointer
 FREECT function
 FREMQQ function
 Function block
 Function designators
 Function parameters
 Functional parameter
 Functional types
 Functions
     A2DRQQ
     A2SRQQ
     ABS
     ACDRQQ
     ACSRQQ
     AIDRQQ
     AISRQQ
     ALLHQQ
     ALLMQQ
     ANDRQQ
     ANSRQQ
     ARCTAN
     arithmetic
     ASDRQQ
     ASSRQQ
     available
         summary of
     BYLONG
     BYWORD
     CHDRQQ
     CHR
     CHSRQQ
     COS
     declarations
     DECODE
     designators
     ENCODE
     EOF
     EOLN
     EXP
 FUnctions
     FLOAT
 Functions
     FLOAT4
     FREECT
     FREMQQ
     GETMQQ
     GETYQQ
     heading
     HIBYTE
     HIWORD
     identifiers
     LADDOK
     LDDRQQ
     LDSRQQ
     LMULOK
     LN
 FUNCTIONS
     LOBYTE
 Functions
     LOCKED
     LOWER
     LOWORD
     MARKAS
     MDDRQQ
     MDSRQQ
     MEMAVL
     MNDRQQ
     MNSRQQ
     MXDRQQ
     MXSRQQ
     ODD
     ORD
     PIDRQQ
     PISRQQ
     POSITN
     RESULT
     RETYPE
     ROUND
     ROUND4
     SADDOK
     SCANEQ
     SCANNE
     SHDRQQ
     SHSRQQ
     SIN
     SIZEOF
     SQR
     SQRT
     SUCC
     THDRQQ
     THSRQQ
     TIC
     TNDRQQ
     TNSRQQ
     TRUNC
     TRUNC4
 FUnctions
     UADDOK
 Functions
     UMULOK
     WRD


 G
 
 GET procedure
 GETMQQ function
 GOTO metacommand
 GOTO statement
 GTYUQQ function


 H
 
 Headings
     function
     procedure
 HIBYTE function
 HIWORD function


 I
 
 Identifiers
     components
     declarations
     definition of
     predeclared
     program
     record field
     restrictions
     scope of
     type
     underscore
 IF metacommand
 IF statement
 Implementations of Pascal
 IN operator
 INCLUDE metacommand
 INCONST metacommand
 INDEXCK metacommand
 Indexed variable
 INITCK metacommand
 INPUT
 INSERT procedure
 INTEGER type
 INTEGER1 predeclared subrange
 INTEGER4 type
 Interactive files
 Interface division
 Interface implementation
 INTERRUPT attribute
 ISO Standard Pascal
 ISO standard
     minor extensions
 ISR operator


 L
 
 Label
 Labels
 LADDOK function
 Language levels
     Standard
 Lazy evaluation
 LDDRQQ function
 LDSRQQ function
 LEN field
 LEN notation
 Letters
 LINE metacommand
 LINESIZE metacommand
 LIST metacommand
 Listing file control
 Listing file format
 LMULOK function
 LN function
 LNDRQQ function
 LNSRQQ function
 LOBYTE function
 LOCKED function
 Loop label
 LOWER function
 LOWORD function
 LSTRING super array type
 LSTRINGS
     passing by reference


 M
 
 M and N formatting parameters
 M parameter
 MARKAS procedure
 MATHCK metacommand
 MAXINT predeclared constant
 MAXINT4 predeclared constant
 MAXWORD predeclared constant
 MDDRQQ function
 MDSRQQ function
 MEMAVL function
 MESSAGE metacommand
 Metacommands
     $brave
     $debug
     $decmath
     $entry
     $errors
     $extend
     $floatcalls
     $goto
     $if/$then/$else
     $include
     $inconst
     $indexck
     $initck
     $line
     $linesize
     $list
     $mathck
     $message
     $nilck
     notation
     $ocode
     optimization
     $page
     $pageif
     $pagesize
     $pop
     $push
     $rangeck
     $rom
     $runtime
     setting language level
     $size
     $skip
     $speed
     $stackck
     $subtitle
     $subtitle
     summary
     $symtab
     $system
     $tagck
     $title
     $title
     $warn
     $warn
 Metaconditional
 Metavariable
 MNDRQQ function
 MNSRQQ function
 MOD operator
 Modules
 MOVEL procedure
 MOVER procedure
 MOVESL procedure
 MOVESR procedure
 MS-Pascal
     comparison with UCSD
     comparisons with other Pascals
 MXDRQQ function
 MXSRQQ function


 N
 
 N and M formatting parameters
 N formatting parameter
 NAN (
 NEW procedure
 NEW procedure
 NILCK metacommand
 Nondecimal numbering
 NOT operator
 Not-A-Number values
 Notation
 NULL
 Null set
 Numeric constant


 O
 
 OCODE metacommand
 ODD function
 Operands
 Operators
     (>)
     (>=)
     (<>)
     (>=)
     (<>)
     (*)
     (+)
     (-)
     (<)
     (<=)
     (=)
     (*)
     (+)
     (-)
     (<=)
     (=)
     (<)
     (\)
     adding
     ADR
     ADS
     AND
     AND THEN
     div
     IN
     ISR
     mod
     multiplying
     NOT
     OR ELSE
     OR
     precedence
     relational
     SHL
     SHR
     unary
     XOR
 Optimization
 OR ELSE
 OR operator
 ORD function
 Ordinal types
 ORIGIN attribute
 OTHERWISE clause
 OUTPUT


 P
 
 PACK procedure
 PACKED
     types
     limitations
 PAGE metacommand
 PAGE procedure
 PAGEIF metacommand
 PAGESIZE metacommand
 Parameters
     actual
     formal
     function
     functional
     procedural
     procedure
     reference
     value
     VARS
 PIDRQQ function
 PISRQQ function
 PLYUQQ procedure
 POP metacommand
 PORT attribute
 POSITN function
 PPMFQQ
 PPMUQQ
 precision of REAL numbers
 PRED function
 Predeclared identifiers
 Predeclared
     constants
         maxint
         maxint4
         maxword
     functions
     procedures
     types
         ADRMEM
         ADSMEM
         FILEMODES
 Procedural parameter
 Procedural types
 Procedure block
 Procedure MOVESR
 Procedure parameters
 Procedure statement
 Procedures
     ABORT
     ASSIGN
     available
         summary of
     BEGOQQ
     BEGXQQ
     CLOSE
     CONCAT
     COPYLST
     COPYSTR
     DATE
     declarations
     DECODE
     DISBIN
     DISCARD
     DISMQQ
     DISPOSE
     ENABIN
     ENDOQQ
     ENDXQQ
     EVAL
     FILLC
     FILLSC
     GET
     heading
     INSERT
     MOVEL
     MOVER
     MOVESL
     NEW
     PACK
     PAGE
     PLYUQQ
     PUT
     READ
     READFN
     READLN
     READSET
     RELEAS
     RESET
     REWRITE
     SMULOK
     SEEK
     TIME
     UNLOCK
     UNPACK
     UPPER
     VECTIN
     WRITE
     WRITELN
 Programs
     heading
     identifiers
     parameters
 PRSRQQ function
 PSDRQQ function
 PTYUQQ procedure
 PUBLIC attribute
 Punctuation
 PURE attribute
 PUSH metacommand
 PUT procedure


 Q
 
 QQ internal naming convention


 R
 
 R address notation
 R notation
 random access files
 RANGECK metacommand
 READ formats
 READ procedure
 READFN procedure
 READLN procedure
 READONLY attribute
 READSET procedure
 REAL type
 REAL
     constants
     precision
 Records
     field offsets
     fields
     variables
 Recursion
 Reference parameters
 Reference variables
 relational operator
 RELEAS procedure
 REPEAT statement
 Repetition statement
 Reserved words
     summary
 RESET procedure
 RESULT function
 RETURN statement
 RETYPE function
 REWRITE procedure
 ROM metacommand
 ROUND function
 ROUND4 function
 RUNTIME metacommand


 S
 
 S address notation
 S address notation
 SADDOK function
 SCANEQ function
 SCANNE function
 SEEK procedure
 Segment parameters
 Semaphores
 Separators
 Sequential control
 SEQUENTIAL
 Sets
     constructors ([ and ])
     expressions
 SHDRQQ function
 SHL operator
 SHR operator
 SHSRQQ function
 Simple statement
 SIN function
 SINT predeclared subrange
 SIZE metacommand
 SIZEOF function
 SKIP metacommand
 SMULOCK procedure
 SNDRQQ function
 SNSRQQ function
 SPEED metacommand
 SQR function
 SQRT function
 SRDRQQ function
 SRSRQQ function
 STACKCK metacommand
 Standard Pascal
 Statements
     assignment
     BREAK
     CASE
     compound
     conditional
     CYCLE
     FOR
     goto
     IF
     procedure
     REPEAT
     repetition
     RETURN
     sequential control
     simple
     structured
     WHILE
     WITH
 STATIC attribute
 String constant
 String reads
 STRING super array type
 Structured constants
 Structured statements
 Structured types
 Subrange
     BYTE predeclared
     INTEGER1 predeclared
     SINT predeclared
 SUBTITLE metacommand
 SUCC function
 Super array parameters
 super array type
 Super types
 SYMTAB metacommand
 Syntactic synonym
 System level intrinsics
 System level Pascal
 SYSTEM metacommand


 T
 
 Tag field
 TAGCK metacommand
 Temporary files
 Terminal input/output routines
 TERMINAL mode
 Textfile I/O
 textfile
 THDRQQ function
 THSRQQ function
 TICS function
 TIME procedure
 TITLE metacommand
 TNDRQQ function
 TNSRQQ function
 TRUNC function
 TRUNC4 function
 Type identity and reference parameters
 Types
     ARRAY
     base
     BOOLEAN
     CHAR
     compatibility
     components
     declaration
     definition
     enumerated
     FILE
     functional
     identifiers of
     identity
     INTEGER
     INTEGER4
     LSTRING
     ordinal
     ordinal
     PACKED
     procedural
     REAL
     records
     reference parameters
     sets
     simple
     STRING
     structured
     subrange
     super arrays
     WORD


 U
 
 UADDOK function
 UCSD Pascal
 UMULOK function
 Underscore
 Units
     constituents
     identifiers
     implementations of
     interfaces
 UNLOCK procedure
 UNPACK procedure
 Unused characters
 Upper bound
 UPPER function


 V
 
 Value parameters
 VALUE section
 Variable length strings
 Variables
     attributes of
     declarations
     initial values
     reference
 VAR
     in FOR statement
     parameters
     sections
 VARS parameters
 Variant records
 VECTIN procedure


 W
 
 WARN metacommand
 WHILE statement
 WITH statement
 WORD type
 WRD function
 WRITE formats
 WRITE procedure
 WRITELN procedure


 X
 
 XOR operator

